1a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall#!/usr/bin/python3 -i 2a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 3a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Copyright (c) 2013-2014 The Khronos Group Inc. 4a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 5a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Permission is hereby granted, free of charge, to any person obtaining a 6a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# copy of this software and/or associated documentation files (the 7a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# "Materials"), to deal in the Materials without restriction, including 8a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# without limitation the rights to use, copy, modify, merge, publish, 9a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# distribute, sublicense, and/or sell copies of the Materials, and to 10a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# permit persons to whom the Materials are furnished to do so, subject to 11a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# the following conditions: 12a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 13a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# The above copyright notice and this permission notice shall be included 14a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# in all copies or substantial portions of the Materials. 15a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 16a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. 23a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 24a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallimport io,os,re,string,sys 25a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallfrom lxml import etree 26a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 27a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef write( *args, **kwargs ): 28a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall file = kwargs.pop('file',sys.stdout) 29a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall end = kwargs.pop( 'end','\n') 30a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall file.write( ' '.join([str(arg) for arg in args]) ) 31a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall file.write( end ) 32a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 33a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# noneStr - returns string argument, or "" if argument is None. 34a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Used in converting lxml Elements into text. 35a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# str - string to convert 36a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef noneStr(str): 37a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (str): 38a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return str 39a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 40a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return "" 41a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 42a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# matchAPIProfile - returns whether an API and profile 43a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# being generated matches an element's profile 44a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# api - string naming the API to match 45a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# profile - string naming the profile to match 46a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# elem - Element which (may) have 'api' and 'profile' 47a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# attributes to match to. 48a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# If a tag is not present in the Element, the corresponding API 49a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# or profile always matches. 50a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Otherwise, the tag must exactly match the API or profile. 51a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Thus, if 'profile' = core: 52a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# <remove> with no attribute will match 53a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# <remove profile='core'> will match 54a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# <remove profile='compatibility'> will not match 55a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Possible match conditions: 56a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Requested Element 57a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Profile Profile 58a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# --------- -------- 59a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# None None Always matches 60a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 'string' None Always matches 61a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# None 'string' Does not match. Can't generate multiple APIs 62a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# or profiles, so if an API/profile constraint 63a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# is present, it must be asked for explicitly. 64a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 'string' 'string' Strings must match 65a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 66a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# ** In the future, we will allow regexes for the attributes, 67a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# not just strings, so that api="^(gl|gles2)" will match. Even 68a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# this isn't really quite enough, we might prefer something 69a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# like "gl(core)|gles1(common-lite)". 70a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef matchAPIProfile(api, profile, elem): 71a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Match a requested API & profile name to a api & profile attributes of an Element""" 72a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall match = True 73a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Match 'api', if present 74a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if ('api' in elem.attrib): 75a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (api == None): 76a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning("No API requested, but 'api' attribute is present with value '" + 77a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elem.get('api') + "'") 78a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (api != elem.get('api')): 79a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Requested API doesn't match attribute 80a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return False 81a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if ('profile' in elem.attrib): 82a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (profile == None): 83a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning("No profile requested, but 'profile' attribute is present with value '" + 84a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elem.get('profile') + "'") 85a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (profile != elem.get('profile')): 86a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Requested profile doesn't match attribute 87a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return False 88a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return True 89a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 90a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# BaseInfo - base class for information about a registry feature 91a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# (type/group/enum/command/API/extension). 92a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# required - should this feature be defined during header generation 93a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# (has it been removed by a profile or version)? 94a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# declared - has this feature been defined already? 95a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# elem - lxml.etree Element for this feature 96a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# resetState() - reset required/declared to initial values. Used 97a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# prior to generating a new API interface. 98a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass BaseInfo: 99a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents the state of a registry feature, used during API generation""" 100a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, elem): 101a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.required = False 102a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.declared = False 103a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.elem = elem 104a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def resetState(self): 105a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.required = False 106a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.declared = False 107a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 108a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# TypeInfo - registry information about a type. No additional state 109a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# beyond BaseInfo is required. 110a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass TypeInfo(BaseInfo): 111a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents the state of a registry type""" 112a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, elem): 113a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall BaseInfo.__init__(self, elem) 114a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 115a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# GroupInfo - registry information about a group of related enums. 116a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# enums - dictionary of enum names which are in the group 117a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass GroupInfo(BaseInfo): 118a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents the state of a registry enumerant group""" 119a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, elem): 120a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall BaseInfo.__init__(self, elem) 121a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enums = {} 122a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 123a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# EnumInfo - registry information about an enum 124a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# type - numeric type of the value of the <enum> tag 125a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 ) 126a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass EnumInfo(BaseInfo): 127a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents the state of a registry enum""" 128a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, elem): 129a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall BaseInfo.__init__(self, elem) 130a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.type = elem.get('type') 131a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.type == None): 132a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.type = '' 133a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 134a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# CmdInfo - registry information about a command 135a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# glxtype - type of GLX protocol { None, 'render', 'single', 'vendor' } 136a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# glxopcode - GLX protocol opcode { None, number } 137a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# glxequiv - equivalent command at GLX dispatch level { None, string } 138a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# vecequiv - equivalent vector form of a command taking multiple scalar args 139a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# { None, string } 140a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass CmdInfo(BaseInfo): 141a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents the state of a registry command""" 142a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, elem): 143a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall BaseInfo.__init__(self, elem) 144a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.glxtype = None 145a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.glxopcode = None 146a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.glxequiv = None 147a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.vecequiv = None 148a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 149a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# FeatureInfo - registry information about an API <feature> 150a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# or <extension> 151a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# name - feature name string (e.g. 'GL_ARB_multitexture') 152a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# number - feature version number (e.g. 1.2). <extension> 153a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# features are unversioned and assigned version number 0. 154a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# category - category, e.g. VERSION or ARB/KHR/OES/ETC/vendor 155a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# emit - has this feature been defined already? 156a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass FeatureInfo(BaseInfo): 157a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents the state of an API feature (version/extension)""" 158a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, elem): 159a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall BaseInfo.__init__(self, elem) 160a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.name = elem.get('name') 161a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Determine element category (vendor). Only works 162a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # for <extension> elements. 163a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (elem.tag == 'feature'): 164a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.category = 'VERSION' 165a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.number = elem.get('number') 166a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 167a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.category = self.name.split('_', 2)[1] 168a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.number = "0" 169a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.emit = False 170a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 171a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Primary sort key for regSortFeatures. 172a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Sorts by category of the feature name string: 173a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Core API features (those defined with a <feature> tag) 174a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# ARB/KHR/OES (Khronos extensions) 175a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# other (EXT/vendor extensions) 176a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef regSortCategoryKey(feature): 177a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (feature.elem.tag == 'feature'): 178a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return 0 179a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (feature.category == 'ARB' or 180a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall feature.category == 'KHR' or 181a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall feature.category == 'OES'): 182a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return 1 183a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 184a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return 2 185a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 186a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Secondary sort key for regSortFeatures. 187a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Sorts by extension name. 188a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef regSortNameKey(feature): 189a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return feature.name 190a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 191a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Tertiary sort key for regSortFeatures. 192a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Sorts by feature version number. <extension> 193a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# elements all have version number "0" 194a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef regSortNumberKey(feature): 195a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return feature.number 196a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 197a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# regSortFeatures - default sort procedure for features. 198a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Sorts by primary key of feature category, 199a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# then by feature name within the category, 200a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# then by version number 201a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Halldef regSortFeatures(featureList): 202a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall featureList.sort(key = regSortNumberKey) 203a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall featureList.sort(key = regSortNameKey) 204a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall featureList.sort(key = regSortCategoryKey) 205a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 206a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# GeneratorOptions - base class for options used during header production 207a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# These options are target language independent, and used by 208a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Registry.apiGen() and by base OutputGenerator objects. 209a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 210a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Members 211a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# filename - name of file to generate, or None to write to stdout. 212a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apiname - string matching <api> 'apiname' attribute, e.g. 'gl'. 213a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# profile - string specifying API profile , e.g. 'core', or None. 214a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# versions - regex matching API versions to process interfaces for. 215a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Normally '.*' or '[0-9]\.[0-9]' to match all defined versions. 216a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# emitversions - regex matching API versions to actually emit 217a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# interfaces for (though all requested versions are considered 218a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# when deciding which interfaces to generate). For GL 4.3 glext.h, 219a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# this might be '1\.[2-5]|[2-4]\.[0-9]'. 220a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# defaultExtensions - If not None, a string which must in its 221a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# entirety match the pattern in the "supported" attribute of 222a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# the <extension>. Defaults to None. Usually the same as apiname. 223a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# addExtensions - regex matching names of additional extensions 224a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# to include. Defaults to None. 2254690754ec38f77431431910ce878850e1c60ab79Pablo Ceballos# removeExtensions - regex matching names of extensions to 226a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# remove (after defaultExtensions and addExtensions). Defaults 227a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# to None. 228a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# sortProcedure - takes a list of FeatureInfo objects and sorts 229a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# them in place to a preferred order in the generated output. 230a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Default is core API versions, ARB/KHR/OES extensions, all 231a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# other extensions, alphabetically within each group. 232a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# The regex patterns can be None or empty, in which case they match 233a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# nothing. 234a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass GeneratorOptions: 235a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents options during header production from an API registry""" 236a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, 237a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall filename = None, 238a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apiname = None, 239a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall profile = None, 240a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall versions = '.*', 241a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall emitversions = '.*', 242a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall defaultExtensions = None, 243a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall addExtensions = None, 244a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall removeExtensions = None, 245a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall sortProcedure = regSortFeatures): 246a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.filename = filename 247a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apiname = apiname 248a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.profile = profile 249a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.versions = self.emptyRegex(versions) 250a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.emitversions = self.emptyRegex(emitversions) 251a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.defaultExtensions = defaultExtensions 252a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addExtensions = self.emptyRegex(addExtensions) 253a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.removeExtensions = self.emptyRegex(removeExtensions) 254a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.sortProcedure = sortProcedure 255a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 256a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Substitute a regular expression which matches no version 257a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # or extension names for None or the empty string. 258a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def emptyRegex(self,pat): 259a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (pat == None or pat == ''): 260a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return '_nomatch_^' 261a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 262a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return pat 263a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 264a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# CGeneratorOptions - subclass of GeneratorOptions. 265a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 266a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Adds options used by COutputGenerator objects during C language header 267a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# generation. 268a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 269a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Additional members 270a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# prefixText - list of strings to prefix generated header with 271a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# (usually a copyright statement + calling convention macros). 272a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# protectFile - True if multiple inclusion protection should be 273a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# generated (based on the filename) around the entire header. 274a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# protectFeature - True if #ifndef..#endif protection should be 275a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# generated around a feature interface in the header file. 276a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genFuncPointers - True if function pointer typedefs should be 277a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# generated 278a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# protectProto - True if #ifdef..#endif protection should be 279a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# generated around prototype declarations 280a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# protectProtoStr - #ifdef symbol to use around prototype 281a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# declarations, if protected 282a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apicall - string to use for the function declaration prefix, 283a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# such as APICALL on Windows. 284a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apientry - string to use for the calling convention macro, 285a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# in typedefs, such as APIENTRY. 286a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apientryp - string to use for the calling convention macro 287a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# in function pointer typedefs, such as APIENTRYP. 288a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass CGeneratorOptions(GeneratorOptions): 289a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents options during C header production from an API registry""" 290a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, 291a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall filename = None, 292a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apiname = None, 293a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall profile = None, 294a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall versions = '.*', 295a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall emitversions = '.*', 296a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall defaultExtensions = None, 297a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall addExtensions = None, 298a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall removeExtensions = None, 299a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall sortProcedure = regSortFeatures, 300a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall prefixText = "", 301a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall genFuncPointers = True, 302a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall protectFile = True, 303a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall protectFeature = True, 304a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall protectProto = True, 305a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall protectProtoStr = True, 306a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apicall = '', 307a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apientry = '', 308a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apientryp = ''): 309a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall GeneratorOptions.__init__(self, filename, apiname, profile, 310a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall versions, emitversions, defaultExtensions, 311a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall addExtensions, removeExtensions, sortProcedure) 312a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.prefixText = prefixText 313a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genFuncPointers = genFuncPointers 314a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.protectFile = protectFile 315a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.protectFeature = protectFeature 316a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.protectProto = protectProto 317a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.protectProtoStr = protectProtoStr 318a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apicall = apicall 319a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apientry = apientry 320a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apientryp = apientryp 321a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 322a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# OutputGenerator - base class for generating API interfaces. 323a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Manages basic logic, logging, and output file control 324a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Derived classes actually generate formatted output. 325a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 326a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# ---- methods ---- 327a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# OutputGenerator(errFile, warnFile, diagFile) 328a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# errFile, warnFile, diagFile - file handles to write errors, 329a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# warnings, diagnostics to. May be None to not write. 330a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# logMsg(level, *args) - log messages of different categories 331a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# level - 'error', 'warn', or 'diag'. 'error' will also 332a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# raise a UserWarning exception 333a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# *args - print()-style arguments 334a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# beginFile(genOpts) - start a new interface file 335a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genOpts - GeneratorOptions controlling what's generated and how 336a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# endFile() - finish an interface file, closing it when done 337a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# beginFeature(interface, emit) - write interface for a feature 338a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# and tag generated features as having been done. 339a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# interface - element for the <version> / <extension> to generate 340a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# emit - actually write to the header only when True 341a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# endFeature() - finish an interface. 342a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genType(typeinfo,name) - generate interface for a type 343a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# typeinfo - TypeInfo for a type 344a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genEnum(enuminfo, name) - generate interface for an enum 345a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# enuminfo - EnumInfo for an enum 346a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# name - enum name 347a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genCmd(cmdinfo) - generate interface for a command 348a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# cmdinfo - CmdInfo for a command 349a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass OutputGenerator: 350a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Generate specified API interfaces in a specific style, such as a C header""" 351a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, 352a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall errFile = sys.stderr, 353a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall warnFile = sys.stderr, 354a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall diagFile = sys.stdout): 355a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.outFile = None 356a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.errFile = errFile 357a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.warnFile = warnFile 358a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.diagFile = diagFile 359a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Internal state 360a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.featureName = None 361a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genOpts = None 362a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 363a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # logMsg - write a message of different categories to different 364a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # destinations. 365a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # level - 366a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 'diag' (diagnostic, voluminous) 367a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 'warn' (warning) 368a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 'error' (fatal error - raises exception after logging) 369a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # *args - print()-style arguments to direct to corresponding log 370a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def logMsg(self, level, *args): 371a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Log a message at the given level. Can be ignored or log to a file""" 372a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (level == 'error'): 373a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall strfile = io.StringIO() 374a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('ERROR:', *args, file=strfile) 375a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.errFile != None): 376a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(strfile.getvalue(), file=self.errFile) 377a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning(strfile.getvalue()) 378a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (level == 'warn'): 379a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.warnFile != None): 380a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('WARNING:', *args, file=self.warnFile) 381a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (level == 'diag'): 382a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.diagFile != None): 383a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('DIAG:', *args, file=self.diagFile) 384a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 385a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning( 386a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall '*** FATAL ERROR in Generator.logMsg: unknown level:' + level) 387a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 388a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def beginFile(self, genOpts): 389a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genOpts = genOpts 390a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 391a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Open specified output file. Not done in constructor since a 392a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Generator can be used without writing to a file. 393a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.filename != None): 394a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.outFile = open(self.genOpts.filename, 'w') 395a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 396a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.outFile = sys.stdout 397a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def endFile(self): 398a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.errFile and self.errFile.flush() 399a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.warnFile and self.warnFile.flush() 400a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.diagFile and self.diagFile.flush() 401a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.outFile.flush() 402a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.outFile != sys.stdout and self.outFile != sys.stderr): 403a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.outFile.close() 404a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genOpts = None 405a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 406a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def beginFeature(self, interface, emit): 407a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.emit = emit 408a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.featureName = interface.get('name') 409a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If there's an additional 'protect' attribute in the feature, save it 410a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.featureExtraProtect = interface.get('protect') 411a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def endFeature(self): 412a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Derived classes responsible for emitting feature 413a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.featureName = None 414a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.featureExtraProtect = None 415a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 416a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Type generation 417a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def genType(self, typeinfo, name): 418a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.featureName == None): 419a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning('Attempt to generate type', name, 420a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'when not in feature') 421a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 422a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Enumerant generation 423a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def genEnum(self, enuminfo, name): 424a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.featureName == None): 425a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning('Attempt to generate enum', name, 426a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'when not in feature') 427a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 428a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Command generation 429a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def genCmd(self, cmd, name): 430a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.featureName == None): 431a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall raise UserWarning('Attempt to generate command', name, 432a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'when not in feature') 433a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 434a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# COutputGenerator - subclass of OutputGenerator. 435a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Generates C-language API interfaces. 436a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# 437a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# ---- methods ---- 438a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# COutputGenerator(errFile, warnFile, diagFile) - args as for 439a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# OutputGenerator. Defines additional internal state. 440a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# makeCDecls(cmd) - return C prototype and function pointer typedef for a 441a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# <command> Element, as a list of two strings 442a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# cmd - Element for the <command> 443a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# newline() - print a newline to the output file (utility function) 444a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# ---- methods overriding base class ---- 445a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# beginFile(genOpts) 446a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# endFile() 447a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# beginFeature(interface, emit) 448a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# endFeature() 449a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genType(typeinfo,name) - generate interface for a type 450a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genEnum(enuminfo, name) 451a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genCmd(cmdinfo) 452a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass COutputGenerator(OutputGenerator): 453a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Generate specified API interfaces in a specific style, such as a C header""" 454a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self, 455a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall errFile = sys.stderr, 456a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall warnFile = sys.stderr, 457a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall diagFile = sys.stdout): 458a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.__init__(self, errFile, warnFile, diagFile) 459a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Internal state - accumulators for different inner block text 460a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.typeBody = '' 461a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumBody = '' 462a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmdBody = '' 463a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 464a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # makeCDecls - return C prototype and function pointer typedef for a 465a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # command, as a two-element list of strings. 466a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # cmd - Element containing a <command> tag 467a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def makeCDecls(self, cmd): 468a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Generate C function pointer typedef for <command> Element""" 469a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall proto = cmd.find('proto') 470a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall params = cmd.findall('param') 471a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Begin accumulating prototype and typedef strings 472a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pdecl = self.genOpts.apicall 473a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall tdecl = 'typedef ' 474a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 475a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Insert the function return type/name. 476a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # For prototypes, add APIENTRY macro before the name 477a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # For typedefs, add (APIENTRYP <name>) around the name and 478a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # use the PFNGLCMDNAMEPROC nameng convention. 479a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Done by walking the tree for <proto> element by element. 480a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # lxml.etree has elem.text followed by (elem[i], elem[i].tail) 481a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # for each child element and any following text 482a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Leading text 483a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pdecl += noneStr(proto.text) 484a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall tdecl += noneStr(proto.text) 485a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # For each child element, if it's a <name> wrap in appropriate 486a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # declaration. Otherwise append its contents and tail contents. 487a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for elem in proto: 488a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall text = noneStr(elem.text) 489a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall tail = noneStr(elem.tail) 490a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (elem.tag == 'name'): 491a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pdecl += self.genOpts.apientry + text + tail 492a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall tdecl += '(' + self.genOpts.apientryp + 'PFN' + text.upper() + 'PROC' + tail + ')' 493a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 494a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pdecl += text + tail 495a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall tdecl += text + tail 496a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Now add the parameter declaration list, which is identical 497a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # for prototypes and typedefs. Concatenate all the text from 498a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # a <param> node without the tags. No tree walking required 499a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # since all tags are ignored. 500a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall n = len(params) 501a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall paramdecl = ' (' 502a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if n > 0: 503a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for i in range(0,n): 504a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall paramdecl += ''.join([t for t in params[i].itertext()]) 505a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (i < n - 1): 506a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall paramdecl += ', ' 507a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 508a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall paramdecl += 'void' 509a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall paramdecl += ");\n"; 510a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return [ pdecl + paramdecl, tdecl + paramdecl ] 511a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 512a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def newline(self): 513a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('', file=self.outFile) 514a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 515a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def beginFile(self, genOpts): 516a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.beginFile(self, genOpts) 517a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # C-specific 518a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 519a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Multiple inclusion protection & C++ wrappers. 520a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (genOpts.protectFile and self.genOpts.filename): 521a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall headerSym = '__' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename)) 522a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#ifndef', headerSym, file=self.outFile) 523a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#define', headerSym, '1', file=self.outFile) 524a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.newline() 525a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#ifdef __cplusplus', file=self.outFile) 526a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('extern "C" {', file=self.outFile) 527a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#endif', file=self.outFile) 528a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.newline() 529a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 530a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # User-supplied prefix text, if any (list of strings) 531a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (genOpts.prefixText): 532a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for s in genOpts.prefixText: 533a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(s, file=self.outFile) 534a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 535a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Some boilerplate describing what was generated - this 536a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # will probably be removed later since the extensions 537a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # pattern may be very long. 538a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('/* Generated C header for:', file=self.outFile) 539a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * API:', genOpts.apiname, file=self.outFile) 540a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (genOpts.profile): 541a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * Profile:', genOpts.profile, file=self.outFile) 542a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * Versions considered:', genOpts.versions, file=self.outFile) 543a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * Versions emitted:', genOpts.emitversions, file=self.outFile) 544a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * Default extensions included:', genOpts.defaultExtensions, file=self.outFile) 545a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * Additional extensions included:', genOpts.addExtensions, file=self.outFile) 546a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' * Extensions removed:', genOpts.removeExtensions, file=self.outFile) 547a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' */', file=self.outFile) 548a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def endFile(self): 549a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # C-specific 550a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Finish C++ wrapper and multiple inclusion protection 551a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.newline() 552a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#ifdef __cplusplus', file=self.outFile) 553a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('}', file=self.outFile) 554a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#endif', file=self.outFile) 555a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.protectFile and self.genOpts.filename): 556a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.newline() 557a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#endif', file=self.outFile) 558a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Finish processing in superclass 559a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.endFile(self) 560a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def beginFeature(self, interface, emit): 561a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Start processing in superclass 562a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.beginFeature(self, interface, emit) 563a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # C-specific 564a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Accumulate types, enums, function pointer typedefs, end function 565a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # prototypes separately for this feature. They're only printed in 566a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # endFeature(). 567a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.typeBody = '' 568a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumBody = '' 569a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmdPointerBody = '' 570a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmdBody = '' 571a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def endFeature(self): 572a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # C-specific 573a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Actually write the interface to the output file. 574a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.emit): 575a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.newline() 576a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.protectFeature): 577a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#ifndef', self.featureName, file=self.outFile) 578a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#define', self.featureName, '1', file=self.outFile) 579a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.typeBody != ''): 580a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(self.typeBody, end='', file=self.outFile) 581a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 582a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Don't add additional protection for derived type declarations, 583a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # which may be needed by other features later on. 584a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.featureExtraProtect != None): 585a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#ifdef', self.featureExtraProtect, file=self.outFile) 586a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.enumBody != ''): 587a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(self.enumBody, end='', file=self.outFile) 588a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.genFuncPointers and self.cmdPointerBody != ''): 589a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(self.cmdPointerBody, end='', file=self.outFile) 590a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.cmdBody != ''): 591a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.protectProto): 592a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#ifdef', self.genOpts.protectProtoStr, file=self.outFile) 593a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(self.cmdBody, end='', file=self.outFile) 594a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.protectProto): 595a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#endif', file=self.outFile) 596a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.featureExtraProtect != None): 597a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) 598a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.protectFeature): 599a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('#endif /*', self.featureName, '*/', file=self.outFile) 600a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Finish processing in superclass 601a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.endFeature(self) 602a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 603a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Type generation 604a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def genType(self, typeinfo, name): 605a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.genType(self, typeinfo, name) 606a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 607a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Replace <apientry /> tags with an APIENTRY-style string 608a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # (from self.genOpts). Copy other text through unchanged. 609a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If the resulting text is an empty string, don't emit it. 610a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall typeElem = typeinfo.elem 611a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall s = noneStr(typeElem.text) 612a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for elem in typeElem: 613a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (elem.tag == 'apientry'): 614a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall s += self.genOpts.apientry + noneStr(elem.tail) 615a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 616a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall s += noneStr(elem.text) + noneStr(elem.tail) 617a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (len(s) > 0): 618a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.typeBody += s + "\n" 619a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 620a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Enumerant generation 621a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def genEnum(self, enuminfo, name): 622a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.genEnum(self, enuminfo, name) 623a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 624a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # EnumInfo.type is a C value suffix (e.g. u, ull) 625a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumBody += '#define ' + name.ljust(33) + ' ' + enuminfo.elem.get('value') 626a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 627a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Handle non-integer 'type' fields by using it as the C value suffix 628a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall t = enuminfo.elem.get('type') 629a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (t != '' and t != 'i'): 630a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumBody += enuminfo.type 631a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumBody += "\n" 632a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 633a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Command generation 634a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def genCmd(self, cmdinfo, name): 635a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall OutputGenerator.genCmd(self, cmdinfo, name) 636a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 637a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall decls = self.makeCDecls(cmdinfo.elem) 638a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmdBody += decls[0] 639a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.genFuncPointers): 640a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmdPointerBody += decls[1] 641a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 642a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Registry - object representing an API registry, loaded from an XML file 643a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Members 644a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# tree - ElementTree containing the root <registry> 645a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# typedict - dictionary of TypeInfo objects keyed by type name 646a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# groupdict - dictionary of GroupInfo objects keyed by group name 647a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# enumdict - dictionary of EnumInfo objects keyed by enum name 648a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# cmddict - dictionary of CmdInfo objects keyed by command name 649a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apidict - dictionary of <api> Elements keyed by API name 650a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# extensions - list of <extension> Elements 651a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# extdict - dictionary of <extension> Elements keyed by extension name 652a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# gen - OutputGenerator object used to write headers / messages 653a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# genOpts - GeneratorOptions object used to control which 654a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# fetures to write and how to format them 655a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# emitFeatures - True to actually emit features for a version / extension, 656a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# or False to just treat them as emitted 657a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Public methods 658a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# loadElementTree(etree) - load registry from specified ElementTree 659a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# loadFile(filename) - load registry from XML file 660a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# setGenerator(gen) - OutputGenerator to use 661a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# parseTree() - parse the registry once loaded & create dictionaries 662a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# dumpReg(maxlen, filehandle) - diagnostic to dump the dictionaries 663a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# to specified file handle (default stdout). Truncates type / 664a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# enum / command elements to maxlen characters (default 80) 665a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# generator(g) - specify the output generator object 666a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apiGen(apiname, genOpts) - generate API headers for the API type 667a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# and profile specified in genOpts, but only for the versions and 668a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# extensions specified there. 669a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# apiReset() - call between calls to apiGen() to reset internal state 670a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# validateGroups() - call to verify that each <proto> or <param> 671a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# with a 'group' attribute matches an actual existing group. 672a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# Private methods 673a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# addElementInfo(elem,info,infoName,dictionary) - add feature info to dict 674a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall# lookupElementInfo(fname,dictionary) - lookup feature info in dict 675a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hallclass Registry: 676a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Represents an API registry loaded from XML""" 677a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def __init__(self): 678a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.tree = None 679a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.typedict = {} 680a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.groupdict = {} 681a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumdict = {} 682a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmddict = {} 683a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apidict = {} 684a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.extensions = [] 685a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.extdict = {} 686a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # A default output generator, so commands prior to apiGen can report 687a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # errors via the generator object. 688a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen = OutputGenerator() 689a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genOpts = None 690a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.emitFeatures = False 691a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def loadElementTree(self, tree): 692a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Load ElementTree into a Registry object and parse it""" 693a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.tree = tree 694a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.parseTree() 695a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def loadFile(self, file): 696a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Load an API registry XML file into a Registry object and parse it""" 697a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.tree = etree.parse(file) 698a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.parseTree() 699a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def setGenerator(self, gen): 700a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Specify output generator object. None restores the default generator""" 701a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen = gen 702a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # addElementInfo - add information about an element to the 703a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # corresponding dictionary 704a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # elem - <type>/<group>/<enum>/<command>/<feature>/<extension> Element 705a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # info - corresponding {Type|Group|Enum|Cmd|Feature}Info object 706a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' 707a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # dictionary - self.{type|group|enum|cmd|api|ext}dict 708a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If the Element has an 'api' attribute, the dictionary key is the 709a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # tuple (name,api). If not, the key is the name. 'name' is an 710a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # attribute of the Element 711a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def addElementInfo(self, elem, info, infoName, dictionary): 712a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if ('api' in elem.attrib): 713a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall key = (elem.get('name'),elem.get('api')) 714a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 715a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall key = elem.get('name') 716a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if key in dictionary: 717a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('warn', '*** Attempt to redefine', 718a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall infoName, 'with key:', key) 719a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 720a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall dictionary[key] = info 721a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 722a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # lookupElementInfo - find a {Type|Enum|Cmd}Info object by name. 723a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If an object qualified by API name exists, use that. 724a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # fname - name of type / enum / command 725a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # dictionary - self.{type|enum|cmd}dict 726a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def lookupElementInfo(self, fname, dictionary): 727a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall key = (fname, self.genOpts.apiname) 728a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (key in dictionary): 729a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # self.gen.logMsg('diag', 'Found API-specific element for feature', fname) 730a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return dictionary[key] 731a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (fname in dictionary): 732a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # self.gen.logMsg('diag', 'Found generic element for feature', fname) 733a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return dictionary[fname] 734a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 735a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return None 736a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def parseTree(self): 737a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Parse the registry Element, once created""" 738a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # This must be the Element for the root <registry> 739a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.reg = self.tree.getroot() 740a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 741a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Create dictionary of registry types from toplevel <types> tags 742a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # and add 'name' attribute to each <type> tag (where missing) 743a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # based on its <name> element. 744a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 745a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # There's usually one <types> block; more are OK 746a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Required <type> attributes: 'name' or nested <name> tag contents 747a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.typedict = {} 748a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for type in self.reg.findall('types/type'): 749a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If the <type> doesn't already have a 'name' attribute, set 750a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # it from contents of its <name> tag. 751a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (type.get('name') == None): 752a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall type.attrib['name'] = type.find('name').text 753a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addElementInfo(type, TypeInfo(type), 'type', self.typedict) 754a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 755a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Create dictionary of registry groups from toplevel <groups> tags. 756a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 757a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # There's usually one <groups> block; more are OK. 758a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Required <group> attributes: 'name' 759a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.groupdict = {} 760a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for group in self.reg.findall('groups/group'): 761a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) 762a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 763a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Create dictionary of registry enums from toplevel <enums> tags 764a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 765a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # There are usually many <enums> tags in different namespaces, but 766a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # these are functional namespaces of the values, while the actual 767a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # enum names all share the dictionary. 768a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Required <enums> attributes: 'name', 'value' 769a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumdict = {} 770a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for enum in self.reg.findall('enums/enum'): 771a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addElementInfo(enum, EnumInfo(enum), 'enum', self.enumdict) 772a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 773a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Create dictionary of registry commands from <command> tags 774a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # and add 'name' attribute to each <command> tag (where missing) 775a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # based on its <proto><name> element. 776a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 777a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # There's usually only one <commands> block; more are OK. 778a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Required <command> attributes: 'name' or <proto><name> tag contents 779a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmddict = {} 780a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for cmd in self.reg.findall('commands/command'): 781a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If the <command> doesn't already have a 'name' attribute, set 782a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # it from contents of its <proto><name> tag. 783a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (cmd.get('name') == None): 784a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall cmd.attrib['name'] = cmd.find('proto/name').text 785a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall ci = CmdInfo(cmd) 786a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addElementInfo(cmd, ci, 'command', self.cmddict) 787a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 788a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Create dictionaries of API and extension interfaces 789a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # from toplevel <api> and <extension> tags. 790a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 791a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apidict = {} 792a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for feature in self.reg.findall('feature'): 793a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall ai = FeatureInfo(feature) 794a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addElementInfo(feature, ai, 'feature', self.apidict) 795a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.extensions = self.reg.findall('extensions/extension') 796a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.extdict = {} 797a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for feature in self.extensions: 798a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall ei = FeatureInfo(feature) 799a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.addElementInfo(feature, ei, 'extension', self.extdict) 800a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def dumpReg(self, maxlen = 40, filehandle = sys.stdout): 801a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Dump all the dictionaries constructed from the Registry object""" 802a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('***************************************', file=filehandle) 803a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' ** Dumping Registry contents **', file=filehandle) 804a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('***************************************', file=filehandle) 805a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('// Types', file=filehandle) 806a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for name in self.typedict: 807a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall tobj = self.typedict[name] 808a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle) 809a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('// Groups', file=filehandle) 810a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for name in self.groupdict: 811a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall gobj = self.groupdict[name] 812a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle) 813a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('// Enums', file=filehandle) 814a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for name in self.enumdict: 815a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall eobj = self.enumdict[name] 816a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle) 817a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('// Commands', file=filehandle) 818a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for name in self.cmddict: 819a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall cobj = self.cmddict[name] 820a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle) 821a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('// APIs', file=filehandle) 822a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for key in self.apidict: 823a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' API Version ', key, '->', 824a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle) 825a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write('// Extensions', file=filehandle) 826a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for key in self.extdict: 827a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall write(' Extension', key, '->', 828a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle) 829a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # write('***************************************', file=filehandle) 830a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # write(' ** Dumping XML ElementTree **', file=filehandle) 831a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # write('***************************************', file=filehandle) 832a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle) 833a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 834a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # typename - name of type 835a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # required - boolean (to tag features as required or not) 836a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def markTypeRequired(self, typename, required): 837a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Require (along with its dependencies) or remove (but not its dependencies) a type""" 838a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** tagging type:', typename, '-> required =', required) 839a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Get TypeInfo object for <type> tag corresponding to typename 840a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall type = self.lookupElementInfo(typename, self.typedict) 841a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (type != None): 842a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Tag required type dependencies as required. 843a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # This DOES NOT un-tag dependencies in a <remove> tag. 844a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # See comments in markRequired() below for the reason. 845a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (required and ('requires' in type.elem.attrib)): 846a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall depType = type.elem.get('requires') 847a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Generating dependent type', 848a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall depType, 'for type', typename) 849a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.markTypeRequired(depType, required) 850a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall type.required = required 851a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 852a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('warn', '*** type:', typename , 'IS NOT DEFINED') 853a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 854a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # features - Element for <require> or <remove> tag 855a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # required - boolean (to tag features as required or not) 856a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def markRequired(self, features, required): 857a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Require or remove features specified in the Element""" 858a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** markRequired (features = <too long to print>, required =', required, ')') 859a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Loop over types, enums, and commands in the tag 860a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # @@ It would be possible to respect 'api' and 'profile' attributes 861a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # in individual features, but that's not done yet. 862a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for typeElem in features.findall('type'): 863a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.markTypeRequired(typeElem.get('name'), required) 864a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for enumElem in features.findall('enum'): 865a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall name = enumElem.get('name') 866a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** tagging enum:', name, '-> required =', required) 867a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall enum = self.lookupElementInfo(name, self.enumdict) 868a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (enum != None): 869a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall enum.required = required 870a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 871a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('warn', '*** enum:', name , 'IS NOT DEFINED') 872a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for cmdElem in features.findall('command'): 873a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall name = cmdElem.get('name') 874a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** tagging command:', name, '-> required =', required) 875a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall cmd = self.lookupElementInfo(name, self.cmddict) 876a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (cmd != None): 877a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall cmd.required = required 878a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Tag all parameter types of this command as required. 879a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # This DOES NOT remove types of commands in a <remove> 880a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # tag, because many other commands may use the same type. 881a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # We could be more clever and reference count types, 882a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # instead of using a boolean. 883a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (required): 884a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Look for <ptype> in entire <command> tree, 885a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # not just immediate children 886a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for ptype in cmd.elem.findall('.//ptype'): 887a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** markRequired: command implicitly requires dependent type', ptype.text) 888a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.markTypeRequired(ptype.text, required) 889a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 890a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('warn', '*** command:', name, 'IS NOT DEFINED') 891a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 892a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # interface - Element for <version> or <extension>, containing 893a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # <require> and <remove> tags 894a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # api - string specifying API name being generated 895a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # profile - string specifying API profile being generated 896a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def requireAndRemoveFeatures(self, interface, api, profile): 897a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Process <recquire> and <remove> tags for a <version> or <extension>""" 898a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # <require> marks things that are required by this version/profile 899a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for feature in interface.findall('require'): 900a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (matchAPIProfile(api, profile, feature)): 901a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.markRequired(feature,True) 902a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # <remove> marks things that are removed by this version/profile 903a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for feature in interface.findall('remove'): 904a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (matchAPIProfile(api, profile, feature)): 905a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.markRequired(feature,False) 906a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 907a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # generateFeature - generate a single type / enum / command, 908a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # and all its dependencies as needed. 909a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # fname - name of feature (<type>/<enum>/<command> 910a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # ftype - type of feature, 'type' | 'enum' | 'command' 911a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # dictionary - of *Info objects - self.{type|enum|cmd}dict 912a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # genProc - bound function pointer for self.gen.gen{Type|Enum|Cmd} 913a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def generateFeature(self, fname, ftype, dictionary, genProc): 914a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall f = self.lookupElementInfo(fname, dictionary) 915a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (f == None): 916a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # No such feature. This is an error, but reported earlier 917a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** No entry found for feature', fname, 918a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'returning!') 919a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return 920a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 921a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If feature isn't required, or has already been declared, return 922a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (not f.required): 923a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not required)') 924a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return 925a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (f.declared): 926a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(already declared)') 927a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall return 928a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 929a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Pull in dependent type declaration(s) of the feature. 930a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # For types, there may be one in the 'required' attribute of the element 931a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # For commands, there may be many in <ptype> tags within the element 932a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # For enums, no dependencies are allowed (though perhasps if you 933a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # have a uint64 enum, it should require GLuint64) 934a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (ftype == 'type'): 935a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if ('requires' in f.elem.attrib): 936a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall depname = f.elem.get('requires') 937a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Generating required dependent type', 938a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall depname) 939a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.generateFeature(depname, 'type', self.typedict, 940a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.genType) 941a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall elif (ftype == 'command'): 942a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for ptype in f.elem.findall('.//ptype'): 943a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall depname = ptype.text 944a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Generating required parameter type', 945a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall depname) 946a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.generateFeature(depname, 'type', self.typedict, 947a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.genType) 948a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 949a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Actually generate the type only if emitting declarations 950a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if self.emitFeatures: 951a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Emitting', ftype, 'decl for', fname) 952a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall genProc(f, fname) 953a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 954a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Skipping', ftype, fname, 955a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall '(not emitting this feature)') 956a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Always mark feature declared, as though actually emitted 957a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall f.declared = True 958a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 959a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # generateRequiredInterface - generate all interfaces required 960a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # by an API version or extension 961a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # interface - Element for <version> or <extension> 962a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def generateRequiredInterface(self, interface): 963a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Generate required C interface for specified API version/extension""" 964a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 965a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Loop over all features inside all <require> tags. 966a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # <remove> tags are ignored (handled in pass 1). 967a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for features in interface.findall('require'): 968a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for t in features.findall('type'): 969a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.generateFeature(t.get('name'), 'type', self.typedict, 970a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.genType) 971a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for e in features.findall('enum'): 972a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.generateFeature(e.get('name'), 'enum', self.enumdict, 973a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.genEnum) 974a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for c in features.findall('command'): 975a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.generateFeature(c.get('name'), 'command', self.cmddict, 976a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.genCmd) 977a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 978a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # apiGen(genOpts) - generate interface for specified versions 979a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # genOpts - GeneratorOptions object with parameters used 980a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # by the Generator object. 981a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def apiGen(self, genOpts): 982a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Generate interfaces for the specified API type and range of versions""" 983a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 984a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*******************************************') 985a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename, 986a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'api:', genOpts.apiname, 987a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'profile:', genOpts.profile) 988a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*******************************************') 989a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 990a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genOpts = genOpts 991a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Reset required/declared flags for all features 992a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apiReset() 993a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 994a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Compile regexps used to select versions & extensions 995a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall regVersions = re.compile(self.genOpts.versions) 996a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall regEmitVersions = re.compile(self.genOpts.emitversions) 997a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall regAddExtensions = re.compile(self.genOpts.addExtensions) 998a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall regRemoveExtensions = re.compile(self.genOpts.removeExtensions) 999a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1000a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Get all matching API versions & add to list of FeatureInfo 1001a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall features = [] 1002a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apiMatch = False 1003a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for key in self.apidict: 1004a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall fi = self.apidict[key] 1005a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall api = fi.elem.get('api') 1006a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (api == self.genOpts.apiname): 1007a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall apiMatch = True 1008a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (regVersions.match(fi.number)): 1009a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Matches API & version #s being generated. Mark for 1010a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # emission and add to the features[] list . 1011a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # @@ Could use 'declared' instead of 'emit'? 1012a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall fi.emit = (regEmitVersions.match(fi.number) != None) 1013a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall features.append(fi) 1014a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (not fi.emit): 1015a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** NOT tagging feature api =', api, 1016a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'name =', fi.name, 'number =', fi.number, 1017a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'for emission (does not match emitversions pattern)') 1018a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 1019a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** NOT including feature api =', api, 1020a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'name =', fi.name, 'number =', fi.number, 1021a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall '(does not match requested versions)') 1022a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 1023a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** NOT including feature api =', api, 1024a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall 'name =', fi.name, 1025a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall '(does not match requested API)') 1026a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (not apiMatch): 1027a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('warn', '*** No matching API versions found!') 1028a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1029a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Get all matching extensions & add to the list. 1030a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Start with extensions tagged with 'api' pattern matching the API 1031a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # being generated. Add extensions matching the pattern specified in 1032a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # regExtensions, then remove extensions matching the pattern 1033a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # specified in regRemoveExtensions 1034a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for key in self.extdict: 1035a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall ei = self.extdict[key] 1036a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall extName = ei.name 1037a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall include = False 1038a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1039a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Include extension if defaultExtensions is not None and if the 1040a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 'supported' attribute matches defaultExtensions. The regexp in 1041a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 'supported' must exactly match defaultExtensions, so bracket 1042a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # it with ^(pat)$. 1043a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pat = '^(' + ei.elem.get('supported') + ')$' 1044a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.defaultExtensions and 1045a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall re.match(pat, self.genOpts.defaultExtensions)): 1046a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Including extension', 1047a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall extName, "(defaultExtensions matches the 'supported' attribute)") 1048a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall include = True 1049a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1050a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Include additional extensions if the extension name matches 1051a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # the regexp specified in the generator options. This allows 1052a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # forcing extensions into an interface even if they're not 1053a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # tagged appropriately in the registry. 1054a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (regAddExtensions.match(extName) != None): 1055a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Including extension', 1056a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall extName, '(matches explicitly requested extensions to add)') 1057a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall include = True 1058a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Remove extensions if the name matches the regexp specified 1059a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # in generator options. This allows forcing removal of 1060a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # extensions from an interface even if they're tagged that 1061a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # way in the registry. 1062a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (regRemoveExtensions.match(extName) != None): 1063a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** Removing extension', 1064a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall extName, '(matches explicitly requested extensions to remove)') 1065a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall include = False 1066a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1067a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If the extension is to be included, add it to the 1068a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # extension features list. 1069a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (include): 1070a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall ei.emit = True 1071a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall features.append(ei) 1072a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 1073a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** NOT including extension', 1074a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall extName, '(does not match api attribute or explicitly requested extensions)') 1075a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1076a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Sort the extension features list, if a sort procedure is defined 1077a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (self.genOpts.sortProcedure): 1078a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.genOpts.sortProcedure(features) 1079a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1080a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Pass 1: loop over requested API versions and extensions tagging 1081a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # types/commands/features as required (in an <require> block) or no 1082a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # longer required (in an <exclude> block). It is possible to remove 1083a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # a feature in one version and restore it later by requiring it in 1084a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # a later version. 1085a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # If a profile other than 'None' is being generated, it must 1086a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # match the profile attribute (if any) of the <require> and 1087a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # <remove> tags. 1088a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** PASS 1: TAG FEATURES ********************************************') 1089a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for f in features: 1090a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** PASS 1: Tagging required and removed features for', 1091a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall f.name) 1092a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.requireAndRemoveFeatures(f.elem, self.genOpts.apiname, self.genOpts.profile) 1093a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1094a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Pass 2: loop over specified API versions and extensions printing 1095a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # declarations for required things which haven't already been 1096a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # generated. 1097a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** PASS 2: GENERATE INTERFACES FOR FEATURES ************************') 1098a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.beginFile(self.genOpts) 1099a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for f in features: 1100a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** PASS 2: Generating interface for', 1101a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall f.name) 1102a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall emit = self.emitFeatures = f.emit 1103a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (not emit): 1104a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** PASS 2: NOT declaring feature', 1105a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall f.elem.get('name'), 'because it is not tagged for emission') 1106a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Generate the interface (or just tag its elements as having been 1107a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # emitted, if they haven't been). 1108a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.beginFeature(f.elem, emit) 1109a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.generateRequiredInterface(f.elem) 1110a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.endFeature() 1111a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.endFile() 1112a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1113a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # apiReset - use between apiGen() calls to reset internal state 1114a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1115a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def apiReset(self): 1116a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Reset type/enum/command dictionaries before generating another API""" 1117a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for type in self.typedict: 1118a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.typedict[type].resetState() 1119a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for enum in self.enumdict: 1120a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.enumdict[enum].resetState() 1121a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for cmd in self.cmddict: 1122a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.cmddict[cmd].resetState() 1123a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for cmd in self.apidict: 1124a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.apidict[cmd].resetState() 1125a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1126a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # validateGroups - check that group= attributes match actual groups 1127a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # 1128a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall def validateGroups(self): 1129a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall """Validate group= attributes on <param> and <proto> tags""" 1130a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # Keep track of group names not in <group> tags 1131a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall badGroup = {} 1132a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** VALIDATING GROUP ATTRIBUTES ***') 1133a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for cmd in self.reg.findall('commands/command'): 1134a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall proto = cmd.find('proto') 1135a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall funcname = cmd.find('proto/name').text 1136a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if ('group' in proto.attrib.keys()): 1137a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall group = proto.get('group') 1138a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # self.gen.logMsg('diag', '*** Command ', funcname, ' has return group ', group) 1139a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (group not in self.groupdict.keys()): 1140a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # self.gen.logMsg('diag', '*** Command ', funcname, ' has UNKNOWN return group ', group) 1141a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (group not in badGroup.keys()): 1142a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall badGroup[group] = 1 1143a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 1144a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall badGroup[group] = badGroup[group] + 1 1145a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for param in cmd.findall('param'): 1146a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pname = param.find('name') 1147a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (pname != None): 1148a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pname = pname.text 1149a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 1150a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall pname = type.get('name') 1151a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if ('group' in param.attrib.keys()): 1152a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall group = param.get('group') 1153a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (group not in self.groupdict.keys()): 1154a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall # self.gen.logMsg('diag', '*** Command ', funcname, ' param ', pname, ' has UNKNOWN group ', group) 1155a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (group not in badGroup.keys()): 1156a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall badGroup[group] = 1 1157a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall else: 1158a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall badGroup[group] = badGroup[group] + 1 1159a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall if (len(badGroup.keys()) > 0): 1160a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', '*** SUMMARY OF UNRECOGNIZED GROUPS ***') 1161a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall for key in sorted(badGroup.keys()): 1162a42788e2b83bf9c1b2471c4ad2af59b8e72333e8Jesse Hall self.gen.logMsg('diag', ' ', key, ' occurred ', badGroup[key], ' times') 1163