1a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan#!/usr/bin/python3 -i 2a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 3a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Copyright (c) 2013-2015 The Khronos Group Inc. 4a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 5a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Permission is hereby granted, free of charge, to any person obtaining a 6a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# copy of this software and/or associated documentation files (the 7a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# "Materials"), to deal in the Materials without restriction, including 8a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# without limitation the rights to use, copy, modify, merge, publish, 9a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# distribute, sublicense, and/or sell copies of the Materials, and to 10a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# permit persons to whom the Materials are furnished to do so, subject to 11a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# the following conditions: 12a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 13a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# The above copyright notice and this permission notice shall be included 14a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# in all copies or substantial portions of the Materials. 15a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 16a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 23a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 24a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanimport io,os,re,string,sys 25a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanfrom lxml import etree 26a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 27a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# matchAPIProfile - returns whether an API and profile 28a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# being generated matches an element's profile 29a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# api - string naming the API to match 30a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# profile - string naming the profile to match 31a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# elem - Element which (may) have 'api' and 'profile' 32a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# attributes to match to. 33a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# If a tag is not present in the Element, the corresponding API 34a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# or profile always matches. 35a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Otherwise, the tag must exactly match the API or profile. 36a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Thus, if 'profile' = core: 37a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# <remove> with no attribute will match 38a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# <remove profile='core'> will match 39a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# <remove profile='compatibility'> will not match 40a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Possible match conditions: 41a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Requested Element 42a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Profile Profile 43a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# --------- -------- 44a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# None None Always matches 45a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 'string' None Always matches 46a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# None 'string' Does not match. Can't generate multiple APIs 47a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# or profiles, so if an API/profile constraint 48a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# is present, it must be asked for explicitly. 49a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 'string' 'string' Strings must match 50a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# 51a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# ** In the future, we will allow regexes for the attributes, 52a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# not just strings, so that api="^(gl|gles2)" will match. Even 53a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# this isn't really quite enough, we might prefer something 54a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# like "gl(core)|gles1(common-lite)". 55a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyandef matchAPIProfile(api, profile, elem): 56a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Match a requested API & profile name to a api & profile attributes of an Element""" 57a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan match = True 58a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Match 'api', if present 59a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('api' in elem.attrib): 60a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (api == None): 61a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan raise UserWarning("No API requested, but 'api' attribute is present with value '" + 62a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elem.get('api') + "'") 63a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elif (api != elem.get('api')): 64a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Requested API doesn't match attribute 65a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return False 66a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('profile' in elem.attrib): 67a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (profile == None): 68a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan raise UserWarning("No profile requested, but 'profile' attribute is present with value '" + 69a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elem.get('profile') + "'") 70a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elif (profile != elem.get('profile')): 71a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Requested profile doesn't match attribute 72a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return False 73a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return True 74a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 75a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# BaseInfo - base class for information about a registry feature 76a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# (type/group/enum/command/API/extension). 77a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# required - should this feature be defined during header generation 78a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# (has it been removed by a profile or version)? 79a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# declared - has this feature been defined already? 80a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# elem - lxml.etree Element for this feature 81a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# resetState() - reset required/declared to initial values. Used 82a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# prior to generating a new API interface. 83a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass BaseInfo: 84a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents the state of a registry feature, used during API generation""" 85a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self, elem): 86a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.required = False 87a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.declared = False 88a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.elem = elem 89a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def resetState(self): 90a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.required = False 91a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.declared = False 92a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 93a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# TypeInfo - registry information about a type. No additional state 94a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# beyond BaseInfo is required. 95a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass TypeInfo(BaseInfo): 96a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents the state of a registry type""" 97a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self, elem): 98a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan BaseInfo.__init__(self, elem) 99a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 100a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# GroupInfo - registry information about a group of related enums 101a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# in an <enums> block, generally corresponding to a C "enum" type. 102a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass GroupInfo(BaseInfo): 103a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents the state of a registry <enums> group""" 104a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self, elem): 105a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan BaseInfo.__init__(self, elem) 106a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 107a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# EnumInfo - registry information about an enum 108a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# type - numeric type of the value of the <enum> tag 109a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 ) 110a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass EnumInfo(BaseInfo): 111a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents the state of a registry enum""" 112a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self, elem): 113a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan BaseInfo.__init__(self, elem) 114a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.type = elem.get('type') 115a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (self.type == None): 116a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.type = '' 117a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 118a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# CmdInfo - registry information about a command 119a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass CmdInfo(BaseInfo): 120a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents the state of a registry command""" 121a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self, elem): 122a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan BaseInfo.__init__(self, elem) 123a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 124a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# FeatureInfo - registry information about an API <feature> 125a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# or <extension> 126a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# name - feature name string (e.g. 'vk_ext_khr_surface') 127a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# version - feature version number (e.g. 1.2). <extension> 128a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# features are unversioned and assigned version number 0. 129a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# ** This is confusingly taken from the 'number' attribute of <feature>. 130a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Needs fixing. 131a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# number - extension number, used for ordering and for 132a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# assigning enumerant offsets. <feature> features do 133a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# not have extension numbers and are assigned number 0. 134a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# category - category, e.g. VERSION or khr/vendor tag 135a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# emit - has this feature been defined already? 136a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass FeatureInfo(BaseInfo): 137a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents the state of an API feature (version/extension)""" 138a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self, elem): 139a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan BaseInfo.__init__(self, elem) 140a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.name = elem.get('name') 141a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Determine element category (vendor). Only works 142a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # for <extension> elements. 143a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (elem.tag == 'feature'): 144a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.category = 'VERSION' 145a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.version = elem.get('number') 146a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.number = "0" 147a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 148a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.category = self.name.split('_', 2)[1] 149a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.version = "0" 150a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.number = elem.get('number') 151a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.emit = False 152a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 153a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanfrom generator import write, GeneratorOptions, OutputGenerator 154a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 155a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Registry - object representing an API registry, loaded from an XML file 156a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Members 157a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# tree - ElementTree containing the root <registry> 158a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# typedict - dictionary of TypeInfo objects keyed by type name 159a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# groupdict - dictionary of GroupInfo objects keyed by group name 160a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# enumdict - dictionary of EnumInfo objects keyed by enum name 161a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# cmddict - dictionary of CmdInfo objects keyed by command name 162a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# apidict - dictionary of <api> Elements keyed by API name 163a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# extensions - list of <extension> Elements 164a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# extdict - dictionary of <extension> Elements keyed by extension name 165a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# gen - OutputGenerator object used to write headers / messages 166a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# genOpts - GeneratorOptions object used to control which 167a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# fetures to write and how to format them 168a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# emitFeatures - True to actually emit features for a version / extension, 169a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# or False to just treat them as emitted 170a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Public methods 171a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# loadElementTree(etree) - load registry from specified ElementTree 172a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# loadFile(filename) - load registry from XML file 173a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# setGenerator(gen) - OutputGenerator to use 174a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# parseTree() - parse the registry once loaded & create dictionaries 175a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# dumpReg(maxlen, filehandle) - diagnostic to dump the dictionaries 176a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# to specified file handle (default stdout). Truncates type / 177a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# enum / command elements to maxlen characters (default 80) 178a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# generator(g) - specify the output generator object 179a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# apiGen(apiname, genOpts) - generate API headers for the API type 180a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# and profile specified in genOpts, but only for the versions and 181a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# extensions specified there. 182a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# apiReset() - call between calls to apiGen() to reset internal state 183a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# Private methods 184a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# addElementInfo(elem,info,infoName,dictionary) - add feature info to dict 185a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan# lookupElementInfo(fname,dictionary) - lookup feature info in dict 186a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyanclass Registry: 187a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Represents an API registry loaded from XML""" 188a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def __init__(self): 189a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.tree = None 190a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.typedict = {} 191a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.groupdict = {} 192a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.enumdict = {} 193a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.cmddict = {} 194a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.apidict = {} 195a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.extensions = [] 196a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.extdict = {} 197a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # A default output generator, so commands prior to apiGen can report 198a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # errors via the generator object. 199a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen = OutputGenerator() 200a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.genOpts = None 201a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.emitFeatures = False 202a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def loadElementTree(self, tree): 203a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Load ElementTree into a Registry object and parse it""" 204a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.tree = tree 205a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.parseTree() 206a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def loadFile(self, file): 207a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Load an API registry XML file into a Registry object and parse it""" 208a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.tree = etree.parse(file) 209a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.parseTree() 210a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def setGenerator(self, gen): 211a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Specify output generator object. None restores the default generator""" 212a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen = gen 213a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.setRegistry(self.tree) 214a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 215a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # addElementInfo - add information about an element to the 216a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # corresponding dictionary 217a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # elem - <type>/<enums>/<enum>/<command>/<feature>/<extension> Element 218a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # info - corresponding {Type|Group|Enum|Cmd|Feature}Info object 219a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' 220a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # dictionary - self.{type|group|enum|cmd|api|ext}dict 221a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If the Element has an 'api' attribute, the dictionary key is the 222a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # tuple (name,api). If not, the key is the name. 'name' is an 223a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # attribute of the Element 224a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def addElementInfo(self, elem, info, infoName, dictionary): 225a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('api' in elem.attrib): 226a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan key = (elem.get('name'),elem.get('api')) 227a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 228a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan key = elem.get('name') 229a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if key in dictionary: 230a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('warn', '*** Attempt to redefine', 231a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan infoName, 'with key:', key) 232a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 233a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan dictionary[key] = info 234a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 235a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # lookupElementInfo - find a {Type|Enum|Cmd}Info object by name. 236a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If an object qualified by API name exists, use that. 237a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # fname - name of type / enum / command 238a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # dictionary - self.{type|enum|cmd}dict 239a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def lookupElementInfo(self, fname, dictionary): 240a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan key = (fname, self.genOpts.apiname) 241a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (key in dictionary): 242a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', 'Found API-specific element for feature', fname) 243a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return dictionary[key] 244a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elif (fname in dictionary): 245a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', 'Found generic element for feature', fname) 246a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return dictionary[fname] 247a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 248a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return None 249a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def parseTree(self): 250a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Parse the registry Element, once created""" 251a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # This must be the Element for the root <registry> 252a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.reg = self.tree.getroot() 253a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 254a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Create dictionary of registry types from toplevel <types> tags 255a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # and add 'name' attribute to each <type> tag (where missing) 256a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # based on its <name> element. 257a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 258a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # There's usually one <types> block; more are OK 259a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Required <type> attributes: 'name' or nested <name> tag contents 260a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.typedict = {} 261a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for type in self.reg.findall('types/type'): 262a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If the <type> doesn't already have a 'name' attribute, set 263a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # it from contents of its <name> tag. 264a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (type.get('name') == None): 265a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan type.attrib['name'] = type.find('name').text 266a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(type, TypeInfo(type), 'type', self.typedict) 267a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 268a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Create dictionary of registry enum groups from <enums> tags. 269a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 270a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Required <enums> attributes: 'name'. If no name is given, one is 271a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # generated, but that group can't be identified and turned into an 272a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # enum type definition - it's just a container for <enum> tags. 273a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.groupdict = {} 274a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for group in self.reg.findall('enums'): 275a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) 276a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 277a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Create dictionary of registry enums from <enum> tags 278a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 279a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <enums> tags usually define different namespaces for the values 280a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # defined in those tags, but the actual names all share the 281a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # same dictionary. 282a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Required <enum> attributes: 'name', 'value' 283a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # For containing <enums> which have type="enum" or type="bitmask", 284a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # tag all contained <enum>s are required. This is a stopgap until 285a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # a better scheme for tagging core and extension enums is created. 286a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.enumdict = {} 287a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for enums in self.reg.findall('enums'): 288a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan required = (enums.get('type') != None) 289a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for enum in enums.findall('enum'): 290a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan enumInfo = EnumInfo(enum) 291a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan enumInfo.required = required 292a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 293a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 294a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Create dictionary of registry commands from <command> tags 295a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # and add 'name' attribute to each <command> tag (where missing) 296a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # based on its <proto><name> element. 297a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 298a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # There's usually only one <commands> block; more are OK. 299a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Required <command> attributes: 'name' or <proto><name> tag contents 300a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.cmddict = {} 301a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for cmd in self.reg.findall('commands/command'): 302a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If the <command> doesn't already have a 'name' attribute, set 303a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # it from contents of its <proto><name> tag. 304a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (cmd.get('name') == None): 305a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan cmd.attrib['name'] = cmd.find('proto/name').text 306a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan ci = CmdInfo(cmd) 307a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(cmd, ci, 'command', self.cmddict) 308a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 309a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Create dictionaries of API and extension interfaces 310a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # from toplevel <api> and <extension> tags. 311a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 312a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.apidict = {} 313a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for feature in self.reg.findall('feature'): 314a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan featureInfo = FeatureInfo(feature) 315a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(feature, featureInfo, 'feature', self.apidict) 316a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.extensions = self.reg.findall('extensions/extension') 317a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.extdict = {} 318a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for feature in self.extensions: 319a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan featureInfo = FeatureInfo(feature) 320a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(feature, featureInfo, 'extension', self.extdict) 321a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 322a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Add additional enums defined only in <extension> tags 323a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # to the corresponding core type. 324a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # When seen here, a copy, processed to contain the numeric enum 325a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # value, is added to the corresponding <enums> element, as well 326a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # as adding to the enum dictionary. Also add a 'extnumber' 327a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # attribute containing the extension number. 328a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 329a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # For <enum> tags which are actually just constants, if there's 330a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # no 'extends' tag but there is a 'value' or 'bitpos' tag, just 331a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # add an EnumInfo record to the dictionary. That works because 332a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # output generation of constants is purely dependency-based, and 333a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # doesn't need to iterate through the XML tags. 334a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 335a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Something like this will need to be done for 'feature's up 336a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # above, if we use the same mechanism for adding to the core 337a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # API in 1.1. 338a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for enum in feature.findall('require/enum'): 339a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan addEnumInfo = False 340a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan groupName = enum.get('extends') 341a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (groupName != None): 342a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', '*** Found extension enum', 343a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # enum.get('name')) 344a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Add extension number attribute to the <enum> element 345a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan enum.attrib['extnumber'] = featureInfo.number 346a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Look up the GroupInfo with matching groupName 347a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (groupName in self.groupdict.keys()): 348a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', '*** Matching group', 349a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # groupName, 'found, adding element...') 350a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan gi = self.groupdict[groupName] 351a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan gi.elem.append(enum) 352a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 353a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('warn', '*** NO matching group', 354a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan groupName, 'for enum', enum.get('name'), 'found.') 355a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan addEnumInfo = True 356a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elif (enum.get('value') or enum.get('bitpos')): 357a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', '*** Adding extension constant "enum"', 358a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # enum.get('name')) 359a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan addEnumInfo = True 360a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (addEnumInfo): 361a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan enumInfo = EnumInfo(enum) 362a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.addElementInfo(enum, enumInfo, 'enum', self.enumdict) 363a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def dumpReg(self, maxlen = 40, filehandle = sys.stdout): 364a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Dump all the dictionaries constructed from the Registry object""" 365a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('***************************************', file=filehandle) 366a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' ** Dumping Registry contents **', file=filehandle) 367a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('***************************************', file=filehandle) 368a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('// Types', file=filehandle) 369a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for name in self.typedict: 370a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan tobj = self.typedict[name] 371a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle) 372a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('// Groups', file=filehandle) 373a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for name in self.groupdict: 374a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan gobj = self.groupdict[name] 375a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle) 376a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('// Enums', file=filehandle) 377a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for name in self.enumdict: 378a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan eobj = self.enumdict[name] 379a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle) 380a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('// Commands', file=filehandle) 381a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for name in self.cmddict: 382a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan cobj = self.cmddict[name] 383a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle) 384a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('// APIs', file=filehandle) 385a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for key in self.apidict: 386a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' API Version ', key, '->', 387a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle) 388a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write('// Extensions', file=filehandle) 389a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for key in self.extdict: 390a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan write(' Extension', key, '->', 391a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle) 392a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # write('***************************************', file=filehandle) 393a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # write(' ** Dumping XML ElementTree **', file=filehandle) 394a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # write('***************************************', file=filehandle) 395a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle) 396a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 397a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # typename - name of type 398a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # required - boolean (to tag features as required or not) 399a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def markTypeRequired(self, typename, required): 400a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Require (along with its dependencies) or remove (but not its dependencies) a type""" 401a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** tagging type:', typename, '-> required =', required) 402a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Get TypeInfo object for <type> tag corresponding to typename 403a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan type = self.lookupElementInfo(typename, self.typedict) 404a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (type != None): 405a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (required): 406a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Tag type dependencies in 'required' attributes as 407a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # required. This DOES NOT un-tag dependencies in a <remove> 408a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # tag. See comments in markRequired() below for the reason. 409a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('requires' in type.elem.attrib): 410a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan depType = type.elem.get('requires') 411a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Generating dependent type', 412a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan depType, 'for type', typename) 413a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markTypeRequired(depType, required) 414a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Tag types used in defining this type (e.g. in nested 415a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <type> tags) 416a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Look for <type> in entire <command> tree, 417a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # not just immediate children 418a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for subtype in type.elem.findall('.//type'): 419a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** markRequired: type requires dependent <type>', subtype.text) 420a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markTypeRequired(subtype.text, required) 421a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Tag enums used in defining this type, for example in 422a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <member><name>member</name>[<enum>MEMBER_SIZE</enum>]</member> 423a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for subenum in type.elem.findall('.//enum'): 424a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** markRequired: type requires dependent <enum>', subenum.text) 425a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markEnumRequired(subenum.text, required) 426a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan type.required = required 427a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 428a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('warn', '*** type:', typename , 'IS NOT DEFINED') 429a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 430a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # enumname - name of enum 431a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # required - boolean (to tag features as required or not) 432a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def markEnumRequired(self, enumname, required): 433a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** tagging enum:', enumname, '-> required =', required) 434a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan enum = self.lookupElementInfo(enumname, self.enumdict) 435a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (enum != None): 436a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan enum.required = required 437a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 438a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('warn', '*** enum:', enumname , 'IS NOT DEFINED') 439a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 440a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # features - Element for <require> or <remove> tag 441a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # required - boolean (to tag features as required or not) 442a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def markRequired(self, features, required): 443a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Require or remove features specified in the Element""" 444a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** markRequired (features = <too long to print>, required =', required, ')') 445a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Loop over types, enums, and commands in the tag 446a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # @@ It would be possible to respect 'api' and 'profile' attributes 447a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # in individual features, but that's not done yet. 448a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for typeElem in features.findall('type'): 449a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markTypeRequired(typeElem.get('name'), required) 450a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for enumElem in features.findall('enum'): 451a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markEnumRequired(enumElem.get('name'), required) 452a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for cmdElem in features.findall('command'): 453a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan name = cmdElem.get('name') 454a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** tagging command:', name, '-> required =', required) 455a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan cmd = self.lookupElementInfo(name, self.cmddict) 456a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (cmd != None): 457a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan cmd.required = required 458a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Tag all parameter types of this command as required. 459a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # This DOES NOT remove types of commands in a <remove> 460a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # tag, because many other commands may use the same type. 461a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # We could be more clever and reference count types, 462a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # instead of using a boolean. 463a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (required): 464a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Look for <type> in entire <command> tree, 465a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # not just immediate children 466a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for type in cmd.elem.findall('.//type'): 467a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** markRequired: command implicitly requires dependent type', type.text) 468a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markTypeRequired(type.text, required) 469a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 470a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('warn', '*** command:', name, 'IS NOT DEFINED') 471a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 472a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # interface - Element for <version> or <extension>, containing 473a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <require> and <remove> tags 474a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # api - string specifying API name being generated 475a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # profile - string specifying API profile being generated 476a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def requireAndRemoveFeatures(self, interface, api, profile): 477a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Process <recquire> and <remove> tags for a <version> or <extension>""" 478a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <require> marks things that are required by this version/profile 479a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for feature in interface.findall('require'): 480a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (matchAPIProfile(api, profile, feature)): 481a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markRequired(feature,True) 482a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <remove> marks things that are removed by this version/profile 483a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for feature in interface.findall('remove'): 484a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (matchAPIProfile(api, profile, feature)): 485a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.markRequired(feature,False) 486a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 487a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # generateFeature - generate a single type / enum group / enum / command, 488a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # and all its dependencies as needed. 489a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # fname - name of feature (<type>/<enum>/<command>) 490a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # ftype - type of feature, 'type' | 'enum' | 'command' 491a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # dictionary - of *Info objects - self.{type|enum|cmd}dict 492a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def generateFeature(self, fname, ftype, dictionary): 493a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan f = self.lookupElementInfo(fname, dictionary) 494a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (f == None): 495a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # No such feature. This is an error, but reported earlier 496a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** No entry found for feature', fname, 497a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'returning!') 498a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return 499a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 500a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If feature isn't required, or has already been declared, return 501a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (not f.required): 502a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not required)') 503a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return 504a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (f.declared): 505a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(already declared)') 506a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan return 507a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Always mark feature declared, as though actually emitted 508a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan f.declared = True 509a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 510a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Pull in dependent declaration(s) of the feature. 511a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # For types, there may be one type in the 'required' attribute of 512a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # the element, as well as many in imbedded <type> and <enum> tags 513a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # within the element. 514a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # For commands, there may be many in <type> tags within the element. 515a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # For enums, no dependencies are allowed (though perhaps if you 516a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # have a uint64 enum, it should require GLuint64). 517a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc = None 518a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (ftype == 'type'): 519a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc = self.gen.genType 520a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('requires' in f.elem.attrib): 521a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan depname = f.elem.get('requires') 522a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Generating required dependent type', 523a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan depname) 524a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(depname, 'type', self.typedict) 525a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for subtype in f.elem.findall('.//type'): 526a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Generating required dependent <type>', 527a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan subtype.text) 528a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(subtype.text, 'type', self.typedict) 529a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for subtype in f.elem.findall('.//enum'): 530a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Generating required dependent <enum>', 531a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan subtype.text) 532a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(subtype.text, 'enum', self.enumdict) 533a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If the type is an enum group, look up the corresponding 534a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # group in the group dictionary and generate that instead. 535a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (f.elem.get('category') == 'enum'): 536a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Type', fname, 'is an enum group, so generate that instead') 537a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan group = self.lookupElementInfo(fname, self.groupdict) 538a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (group == None): 539a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Unless this is tested for, it's probably fatal to call below 540a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc = None 541a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.logMsg('warn', '*** NO MATCHING ENUM GROUP FOUND!!!') 542a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 543a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc = self.gen.genGroup 544a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan f = group 545a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elif (ftype == 'command'): 546a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc = self.gen.genCmd 547a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for type in f.elem.findall('.//type'): 548a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan depname = type.text 549a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Generating required parameter type', 550a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan depname) 551a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(depname, 'type', self.typedict) 552a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan elif (ftype == 'enum'): 553a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc = self.gen.genEnum 554a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Actually generate the type only if emitting declarations 555a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if self.emitFeatures: 556a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Emitting', ftype, 'decl for', fname) 557a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan genProc(f, fname) 558a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 559a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Skipping', ftype, fname, 560a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan '(not emitting this feature)') 561a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 562a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # generateRequiredInterface - generate all interfaces required 563a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # by an API version or extension 564a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # interface - Element for <version> or <extension> 565a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def generateRequiredInterface(self, interface): 566a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Generate required C interface for specified API version/extension""" 567a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 568a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Loop over all features inside all <require> tags. 569a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <remove> tags are ignored (handled in pass 1). 570a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for features in interface.findall('require'): 571a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for t in features.findall('type'): 572a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(t.get('name'), 'type', self.typedict) 573a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for e in features.findall('enum'): 574a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(e.get('name'), 'enum', self.enumdict) 575a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for c in features.findall('command'): 576a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateFeature(c.get('name'), 'command', self.cmddict) 577a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 578a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # apiGen(genOpts) - generate interface for specified versions 579a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # genOpts - GeneratorOptions object with parameters used 580a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # by the Generator object. 581a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def apiGen(self, genOpts): 582a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Generate interfaces for the specified API type and range of versions""" 583a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 584a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*******************************************') 585a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename, 586a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'api:', genOpts.apiname, 587a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'profile:', genOpts.profile) 588a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*******************************************') 589a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 590a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.genOpts = genOpts 591a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Reset required/declared flags for all features 592a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.apiReset() 593a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 594a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Compile regexps used to select versions & extensions 595a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan regVersions = re.compile(self.genOpts.versions) 596a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan regEmitVersions = re.compile(self.genOpts.emitversions) 597a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan regAddExtensions = re.compile(self.genOpts.addExtensions) 598a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan regRemoveExtensions = re.compile(self.genOpts.removeExtensions) 599a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 600a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Get all matching API versions & add to list of FeatureInfo 601a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan features = [] 602a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan apiMatch = False 603a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for key in self.apidict: 604a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan fi = self.apidict[key] 605a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan api = fi.elem.get('api') 606a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (api == self.genOpts.apiname): 607a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan apiMatch = True 608a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (regVersions.match(fi.version)): 609a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Matches API & version #s being generated. Mark for 610a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # emission and add to the features[] list . 611a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # @@ Could use 'declared' instead of 'emit'? 612a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan fi.emit = (regEmitVersions.match(fi.version) != None) 613a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan features.append(fi) 614a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (not fi.emit): 615a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** NOT tagging feature api =', api, 616a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'name =', fi.name, 'version =', fi.version, 617a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'for emission (does not match emitversions pattern)') 618a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 619a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** NOT including feature api =', api, 620a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'name =', fi.name, 'version =', fi.version, 621a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan '(does not match requested versions)') 622a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 623a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** NOT including feature api =', api, 624a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan 'name =', fi.name, 625a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan '(does not match requested API)') 626a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (not apiMatch): 627a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('warn', '*** No matching API versions found!') 628a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 629a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Get all matching extensions, in order by their extension number, 630a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # and add to the list of features. 631a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Start with extensions tagged with 'api' pattern matching the API 632a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # being generated. Add extensions matching the pattern specified in 633a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # regExtensions, then remove extensions matching the pattern 634a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # specified in regRemoveExtensions 635a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for (extName,ei) in sorted(self.extdict.items(),key = lambda x : x[1].number): 636a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan extName = ei.name 637a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan include = False 638a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 639a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Include extension if defaultExtensions is not None and if the 640a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 'supported' attribute matches defaultExtensions. The regexp in 641a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 'supported' must exactly match defaultExtensions, so bracket 642a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # it with ^(pat)$. 643a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan pat = '^(' + ei.elem.get('supported') + ')$' 644a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (self.genOpts.defaultExtensions and 645a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan re.match(pat, self.genOpts.defaultExtensions)): 646a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Including extension', 647a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan extName, "(defaultExtensions matches the 'supported' attribute)") 648a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan include = True 649a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 650a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Include additional extensions if the extension name matches 651a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # the regexp specified in the generator options. This allows 652a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # forcing extensions into an interface even if they're not 653a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # tagged appropriately in the registry. 654a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (regAddExtensions.match(extName) != None): 655a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Including extension', 656a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan extName, '(matches explicitly requested extensions to add)') 657a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan include = True 658a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Remove extensions if the name matches the regexp specified 659a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # in generator options. This allows forcing removal of 660a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # extensions from an interface even if they're tagged that 661a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # way in the registry. 662a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (regRemoveExtensions.match(extName) != None): 663a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** Removing extension', 664a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan extName, '(matches explicitly requested extensions to remove)') 665a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan include = False 666a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 667a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If the extension is to be included, add it to the 668a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # extension features list. 669a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (include): 670a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan ei.emit = True 671a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan features.append(ei) 672a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 673a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** NOT including extension', 674a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan extName, '(does not match api attribute or explicitly requested extensions)') 675a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 676a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Sort the extension features list, if a sort procedure is defined 677a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (self.genOpts.sortProcedure): 678a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.genOpts.sortProcedure(features) 679a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 680a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Pass 1: loop over requested API versions and extensions tagging 681a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # types/commands/features as required (in an <require> block) or no 682a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # longer required (in an <remove> block). It is possible to remove 683a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # a feature in one version and restore it later by requiring it in 684a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # a later version. 685a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # If a profile other than 'None' is being generated, it must 686a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # match the profile attribute (if any) of the <require> and 687a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # <remove> tags. 688a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** PASS 1: TAG FEATURES ********************************************') 689a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for f in features: 690a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** PASS 1: Tagging required and removed features for', 691a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan f.name) 692a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.requireAndRemoveFeatures(f.elem, self.genOpts.apiname, self.genOpts.profile) 693a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 694a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Pass 2: loop over specified API versions and extensions printing 695a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # declarations for required things which haven't already been 696a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # generated. 697a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** PASS 2: GENERATE INTERFACES FOR FEATURES ************************') 698a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.beginFile(self.genOpts) 699a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for f in features: 700a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** PASS 2: Generating interface for', 701a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan f.name) 702a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan emit = self.emitFeatures = f.emit 703a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (not emit): 704a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** PASS 2: NOT declaring feature', 705a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan f.elem.get('name'), 'because it is not tagged for emission') 706a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Generate the interface (or just tag its elements as having been 707a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # emitted, if they haven't been). 708a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.beginFeature(f.elem, emit) 709a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.generateRequiredInterface(f.elem) 710a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.endFeature() 711a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.endFile() 712a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 713a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # apiReset - use between apiGen() calls to reset internal state 714a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 715a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def apiReset(self): 716a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Reset type/enum/command dictionaries before generating another API""" 717a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for type in self.typedict: 718a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.typedict[type].resetState() 719a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for enum in self.enumdict: 720a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.enumdict[enum].resetState() 721a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for cmd in self.cmddict: 722a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.cmddict[cmd].resetState() 723a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for cmd in self.apidict: 724a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.apidict[cmd].resetState() 725a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 726a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # validateGroups - check that group= attributes match actual groups 727a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # 728a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan def validateGroups(self): 729a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan """Validate group= attributes on <param> and <proto> tags""" 730a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # Keep track of group names not in <group> tags 731a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan badGroup = {} 732a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** VALIDATING GROUP ATTRIBUTES ***') 733a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for cmd in self.reg.findall('commands/command'): 734a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan proto = cmd.find('proto') 735a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan funcname = cmd.find('proto/name').text 736a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('group' in proto.attrib.keys()): 737a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan group = proto.get('group') 738a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', '*** Command ', funcname, ' has return group ', group) 739a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (group not in self.groupdict.keys()): 740a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', '*** Command ', funcname, ' has UNKNOWN return group ', group) 741a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (group not in badGroup.keys()): 742a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan badGroup[group] = 1 743a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 744a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan badGroup[group] = badGroup[group] + 1 745a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for param in cmd.findall('param'): 746a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan pname = param.find('name') 747a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (pname != None): 748a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan pname = pname.text 749a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 750a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan pname = type.get('name') 751a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if ('group' in param.attrib.keys()): 752a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan group = param.get('group') 753a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (group not in self.groupdict.keys()): 754a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan # self.gen.logMsg('diag', '*** Command ', funcname, ' param ', pname, ' has UNKNOWN group ', group) 755a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (group not in badGroup.keys()): 756a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan badGroup[group] = 1 757a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan else: 758a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan badGroup[group] = badGroup[group] + 1 759a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan if (len(badGroup.keys()) > 0): 760a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', '*** SUMMARY OF UNRECOGNIZED GROUPS ***') 761a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan for key in sorted(badGroup.keys()): 762a451fa8bcbde4ba46bd83055f6624f812dd7996fMike Stroyan self.gen.logMsg('diag', ' ', key, ' occurred ', badGroup[key], ' times') 763