15bd8deadSopenharmony_ci#!/usr/bin/python3 -i 25bd8deadSopenharmony_ci# 35bd8deadSopenharmony_ci# Copyright 2013-2020 The Khronos Group Inc. 45bd8deadSopenharmony_ci# SPDX-License-Identifier: Apache-2.0 55bd8deadSopenharmony_ci 65bd8deadSopenharmony_ciimport io,os,re,string,sys 75bd8deadSopenharmony_cifrom lxml import etree 85bd8deadSopenharmony_ci 95bd8deadSopenharmony_cidef write(*args, **kwargs): 105bd8deadSopenharmony_ci file = kwargs.pop('file', sys.stdout) 115bd8deadSopenharmony_ci end = kwargs.pop('end', '\n') 125bd8deadSopenharmony_ci file.write(' '.join([str(arg) for arg in args])) 135bd8deadSopenharmony_ci file.write(end) 145bd8deadSopenharmony_ci 155bd8deadSopenharmony_ci# noneStr - returns string argument, or "" if argument is None. 165bd8deadSopenharmony_ci# Used in converting lxml Elements into text. 175bd8deadSopenharmony_ci# str - string to convert 185bd8deadSopenharmony_cidef noneStr(str): 195bd8deadSopenharmony_ci if (str): 205bd8deadSopenharmony_ci return str 215bd8deadSopenharmony_ci else: 225bd8deadSopenharmony_ci return "" 235bd8deadSopenharmony_ci 245bd8deadSopenharmony_ci# matchAPIProfile - returns whether an API and profile 255bd8deadSopenharmony_ci# being generated matches an element's profile 265bd8deadSopenharmony_ci# api - string naming the API to match 275bd8deadSopenharmony_ci# profile - string naming the profile to match 285bd8deadSopenharmony_ci# elem - Element which (may) have 'api' and 'profile' 295bd8deadSopenharmony_ci# attributes to match to. 305bd8deadSopenharmony_ci# If a tag is not present in the Element, the corresponding API 315bd8deadSopenharmony_ci# or profile always matches. 325bd8deadSopenharmony_ci# Otherwise, the tag must exactly match the API or profile. 335bd8deadSopenharmony_ci# Thus, if 'profile' = core: 345bd8deadSopenharmony_ci# <remove> with no attribute will match 355bd8deadSopenharmony_ci# <remove profile='core'> will match 365bd8deadSopenharmony_ci# <remove profile='compatibility'> will not match 375bd8deadSopenharmony_ci# Possible match conditions: 385bd8deadSopenharmony_ci# Requested Element 395bd8deadSopenharmony_ci# Profile Profile 405bd8deadSopenharmony_ci# --------- -------- 415bd8deadSopenharmony_ci# None None Always matches 425bd8deadSopenharmony_ci# 'string' None Always matches 435bd8deadSopenharmony_ci# None 'string' Does not match. Can't generate multiple APIs 445bd8deadSopenharmony_ci# or profiles, so if an API/profile constraint 455bd8deadSopenharmony_ci# is present, it must be asked for explicitly. 465bd8deadSopenharmony_ci# 'string' 'string' Strings must match 475bd8deadSopenharmony_ci# 485bd8deadSopenharmony_ci# ** In the future, we will allow regexes for the attributes, 495bd8deadSopenharmony_ci# not just strings, so that api="^(gl|gles2)" will match. Even 505bd8deadSopenharmony_ci# this isn't really quite enough, we might prefer something 515bd8deadSopenharmony_ci# like "gl(core)|gles1(common-lite)". 525bd8deadSopenharmony_cidef matchAPIProfile(api, profile, elem): 535bd8deadSopenharmony_ci """Match a requested API & profile name to a api & profile attributes of an Element""" 545bd8deadSopenharmony_ci match = True 555bd8deadSopenharmony_ci # Match 'api', if present 565bd8deadSopenharmony_ci if ('api' in elem.attrib): 575bd8deadSopenharmony_ci if (api == None): 585bd8deadSopenharmony_ci raise UserWarning("No API requested, but 'api' attribute is present with value '" + 595bd8deadSopenharmony_ci elem.get('api') + "'") 605bd8deadSopenharmony_ci elif (api != elem.get('api')): 615bd8deadSopenharmony_ci # Requested API doesn't match attribute 625bd8deadSopenharmony_ci return False 635bd8deadSopenharmony_ci if ('profile' in elem.attrib): 645bd8deadSopenharmony_ci if (profile == None): 655bd8deadSopenharmony_ci raise UserWarning("No profile requested, but 'profile' attribute is present with value '" + 665bd8deadSopenharmony_ci elem.get('profile') + "'") 675bd8deadSopenharmony_ci elif (profile != elem.get('profile')): 685bd8deadSopenharmony_ci # Requested profile doesn't match attribute 695bd8deadSopenharmony_ci return False 705bd8deadSopenharmony_ci return True 715bd8deadSopenharmony_ci 725bd8deadSopenharmony_ci# BaseInfo - base class for information about a registry feature 735bd8deadSopenharmony_ci# (type/group/enum/command/API/extension). 745bd8deadSopenharmony_ci# required - should this feature be defined during header generation 755bd8deadSopenharmony_ci# (has it been removed by a profile or version)? 765bd8deadSopenharmony_ci# declared - has this feature been defined already? 775bd8deadSopenharmony_ci# elem - lxml.etree Element for this feature 785bd8deadSopenharmony_ci# resetState() - reset required/declared to initial values. Used 795bd8deadSopenharmony_ci# prior to generating a new API interface. 805bd8deadSopenharmony_ciclass BaseInfo: 815bd8deadSopenharmony_ci """Represents the state of a registry feature, used during API generation""" 825bd8deadSopenharmony_ci def __init__(self, elem): 835bd8deadSopenharmony_ci self.required = False 845bd8deadSopenharmony_ci self.declared = False 855bd8deadSopenharmony_ci self.elem = elem 865bd8deadSopenharmony_ci def resetState(self): 875bd8deadSopenharmony_ci self.required = False 885bd8deadSopenharmony_ci self.declared = False 895bd8deadSopenharmony_ci 905bd8deadSopenharmony_ci# TypeInfo - registry information about a type. No additional state 915bd8deadSopenharmony_ci# beyond BaseInfo is required. 925bd8deadSopenharmony_ciclass TypeInfo(BaseInfo): 935bd8deadSopenharmony_ci """Represents the state of a registry type""" 945bd8deadSopenharmony_ci def __init__(self, elem): 955bd8deadSopenharmony_ci BaseInfo.__init__(self, elem) 965bd8deadSopenharmony_ci 975bd8deadSopenharmony_ci# GroupInfo - registry information about a group of related enums. 985bd8deadSopenharmony_ci# enums - dictionary of enum names which are in the group 995bd8deadSopenharmony_ciclass GroupInfo(BaseInfo): 1005bd8deadSopenharmony_ci """Represents the state of a registry enumerant group""" 1015bd8deadSopenharmony_ci def __init__(self, elem): 1025bd8deadSopenharmony_ci BaseInfo.__init__(self, elem) 1035bd8deadSopenharmony_ci self.enums = {} 1045bd8deadSopenharmony_ci 1055bd8deadSopenharmony_ci# EnumInfo - registry information about an enum 1065bd8deadSopenharmony_ci# type - numeric type of the value of the <enum> tag 1075bd8deadSopenharmony_ci# ( '' for GLint, 'u' for GLuint, 'ull' for GLuint64 ) 1085bd8deadSopenharmony_ciclass EnumInfo(BaseInfo): 1095bd8deadSopenharmony_ci """Represents the state of a registry enum""" 1105bd8deadSopenharmony_ci def __init__(self, elem): 1115bd8deadSopenharmony_ci BaseInfo.__init__(self, elem) 1125bd8deadSopenharmony_ci self.type = elem.get('type') 1135bd8deadSopenharmony_ci if (self.type == None): 1145bd8deadSopenharmony_ci self.type = '' 1155bd8deadSopenharmony_ci 1165bd8deadSopenharmony_ci# CmdInfo - registry information about a command 1175bd8deadSopenharmony_ci# glxtype - type of GLX protocol { None, 'render', 'single', 'vendor' } 1185bd8deadSopenharmony_ci# glxopcode - GLX protocol opcode { None, number } 1195bd8deadSopenharmony_ci# glxequiv - equivalent command at GLX dispatch level { None, string } 1205bd8deadSopenharmony_ci# vecequiv - equivalent vector form of a command taking multiple scalar args 1215bd8deadSopenharmony_ci# { None, string } 1225bd8deadSopenharmony_ciclass CmdInfo(BaseInfo): 1235bd8deadSopenharmony_ci """Represents the state of a registry command""" 1245bd8deadSopenharmony_ci def __init__(self, elem): 1255bd8deadSopenharmony_ci BaseInfo.__init__(self, elem) 1265bd8deadSopenharmony_ci self.glxtype = None 1275bd8deadSopenharmony_ci self.glxopcode = None 1285bd8deadSopenharmony_ci self.glxequiv = None 1295bd8deadSopenharmony_ci self.vecequiv = None 1305bd8deadSopenharmony_ci 1315bd8deadSopenharmony_ci# FeatureInfo - registry information about an API <feature> 1325bd8deadSopenharmony_ci# or <extension> 1335bd8deadSopenharmony_ci# name - feature name string (e.g. 'GL_ARB_multitexture') 1345bd8deadSopenharmony_ci# number - feature version number (e.g. 1.2). <extension> 1355bd8deadSopenharmony_ci# features are unversioned and assigned version number 0. 1365bd8deadSopenharmony_ci# category - category, e.g. VERSION or ARB/KHR/OES/ETC/vendor 1375bd8deadSopenharmony_ci# emit - has this feature been defined already? 1385bd8deadSopenharmony_ciclass FeatureInfo(BaseInfo): 1395bd8deadSopenharmony_ci """Represents the state of an API feature (version/extension)""" 1405bd8deadSopenharmony_ci def __init__(self, elem): 1415bd8deadSopenharmony_ci BaseInfo.__init__(self, elem) 1425bd8deadSopenharmony_ci self.name = elem.get('name') 1435bd8deadSopenharmony_ci # Determine element category (vendor). Only works 1445bd8deadSopenharmony_ci # for <extension> elements. 1455bd8deadSopenharmony_ci if (elem.tag == 'feature'): 1465bd8deadSopenharmony_ci self.category = 'VERSION' 1475bd8deadSopenharmony_ci self.number = elem.get('number') 1485bd8deadSopenharmony_ci else: 1495bd8deadSopenharmony_ci self.category = self.name.split('_', 2)[1] 1505bd8deadSopenharmony_ci self.number = "0" 1515bd8deadSopenharmony_ci self.emit = False 1525bd8deadSopenharmony_ci 1535bd8deadSopenharmony_ci# Primary sort key for regSortFeatures. 1545bd8deadSopenharmony_ci# Sorts by category of the feature name string: 1555bd8deadSopenharmony_ci# Core API features (those defined with a <feature> tag) 1565bd8deadSopenharmony_ci# ARB/KHR/OES (Khronos extensions) 1575bd8deadSopenharmony_ci# other (EXT/vendor extensions) 1585bd8deadSopenharmony_cidef regSortCategoryKey(feature): 1595bd8deadSopenharmony_ci if (feature.elem.tag == 'feature'): 1605bd8deadSopenharmony_ci return 0 1615bd8deadSopenharmony_ci elif (feature.category == 'ARB' or 1625bd8deadSopenharmony_ci feature.category == 'KHR' or 1635bd8deadSopenharmony_ci feature.category == 'OES'): 1645bd8deadSopenharmony_ci return 1 1655bd8deadSopenharmony_ci else: 1665bd8deadSopenharmony_ci return 2 1675bd8deadSopenharmony_ci 1685bd8deadSopenharmony_ci# Secondary sort key for regSortFeatures. 1695bd8deadSopenharmony_ci# Sorts by extension name. 1705bd8deadSopenharmony_cidef regSortNameKey(feature): 1715bd8deadSopenharmony_ci return feature.name 1725bd8deadSopenharmony_ci 1735bd8deadSopenharmony_ci# Tertiary sort key for regSortFeatures. 1745bd8deadSopenharmony_ci# Sorts by feature version number. <extension> 1755bd8deadSopenharmony_ci# elements all have version number "0" 1765bd8deadSopenharmony_cidef regSortNumberKey(feature): 1775bd8deadSopenharmony_ci return feature.number 1785bd8deadSopenharmony_ci 1795bd8deadSopenharmony_ci# regSortFeatures - default sort procedure for features. 1805bd8deadSopenharmony_ci# Sorts by primary key of feature category, 1815bd8deadSopenharmony_ci# then by feature name within the category, 1825bd8deadSopenharmony_ci# then by version number 1835bd8deadSopenharmony_cidef regSortFeatures(featureList): 1845bd8deadSopenharmony_ci featureList.sort(key = regSortNumberKey) 1855bd8deadSopenharmony_ci featureList.sort(key = regSortNameKey) 1865bd8deadSopenharmony_ci featureList.sort(key = regSortCategoryKey) 1875bd8deadSopenharmony_ci 1885bd8deadSopenharmony_ci# GeneratorOptions - base class for options used during header production 1895bd8deadSopenharmony_ci# These options are target language independent, and used by 1905bd8deadSopenharmony_ci# Registry.apiGen() and by base OutputGenerator objects. 1915bd8deadSopenharmony_ci# 1925bd8deadSopenharmony_ci# Members 1935bd8deadSopenharmony_ci# filename - name of file to generate, or None to write to stdout. 1945bd8deadSopenharmony_ci# apiname - string matching <api> 'apiname' attribute, e.g. 'gl'. 1955bd8deadSopenharmony_ci# profile - string specifying API profile , e.g. 'core', or None. 1965bd8deadSopenharmony_ci# versions - regex matching API versions to process interfaces for. 1975bd8deadSopenharmony_ci# Normally '.*' or '[0-9]\.[0-9]' to match all defined versions. 1985bd8deadSopenharmony_ci# emitversions - regex matching API versions to actually emit 1995bd8deadSopenharmony_ci# interfaces for (though all requested versions are considered 2005bd8deadSopenharmony_ci# when deciding which interfaces to generate). For GL 4.3 glext.h, 2015bd8deadSopenharmony_ci# this might be '1\.[2-5]|[2-4]\.[0-9]'. 2025bd8deadSopenharmony_ci# defaultExtensions - If not None, a string which must in its 2035bd8deadSopenharmony_ci# entirety match the pattern in the "supported" attribute of 2045bd8deadSopenharmony_ci# the <extension>. Defaults to None. Usually the same as apiname. 2055bd8deadSopenharmony_ci# addExtensions - regex matching names of additional extensions 2065bd8deadSopenharmony_ci# to include. Defaults to None. 2075bd8deadSopenharmony_ci# removeExtensions - regex matching names of extensions to 2085bd8deadSopenharmony_ci# remove (after defaultExtensions and addExtensions). Defaults 2095bd8deadSopenharmony_ci# to None. 2105bd8deadSopenharmony_ci# sortProcedure - takes a list of FeatureInfo objects and sorts 2115bd8deadSopenharmony_ci# them in place to a preferred order in the generated output. 2125bd8deadSopenharmony_ci# Default is core API versions, ARB/KHR/OES extensions, all 2135bd8deadSopenharmony_ci# other extensions, alphabetically within each group. 2145bd8deadSopenharmony_ci# The regex patterns can be None or empty, in which case they match 2155bd8deadSopenharmony_ci# nothing. 2165bd8deadSopenharmony_ciclass GeneratorOptions: 2175bd8deadSopenharmony_ci """Represents options during header production from an API registry""" 2185bd8deadSopenharmony_ci def __init__(self, 2195bd8deadSopenharmony_ci filename = None, 2205bd8deadSopenharmony_ci apiname = None, 2215bd8deadSopenharmony_ci profile = None, 2225bd8deadSopenharmony_ci versions = '.*', 2235bd8deadSopenharmony_ci emitversions = '.*', 2245bd8deadSopenharmony_ci defaultExtensions = None, 2255bd8deadSopenharmony_ci addExtensions = None, 2265bd8deadSopenharmony_ci removeExtensions = None, 2275bd8deadSopenharmony_ci sortProcedure = regSortFeatures): 2285bd8deadSopenharmony_ci self.filename = filename 2295bd8deadSopenharmony_ci self.apiname = apiname 2305bd8deadSopenharmony_ci self.profile = profile 2315bd8deadSopenharmony_ci self.versions = self.emptyRegex(versions) 2325bd8deadSopenharmony_ci self.emitversions = self.emptyRegex(emitversions) 2335bd8deadSopenharmony_ci self.defaultExtensions = defaultExtensions 2345bd8deadSopenharmony_ci self.addExtensions = self.emptyRegex(addExtensions) 2355bd8deadSopenharmony_ci self.removeExtensions = self.emptyRegex(removeExtensions) 2365bd8deadSopenharmony_ci self.sortProcedure = sortProcedure 2375bd8deadSopenharmony_ci # 2385bd8deadSopenharmony_ci # Substitute a regular expression which matches no version 2395bd8deadSopenharmony_ci # or extension names for None or the empty string. 2405bd8deadSopenharmony_ci def emptyRegex(self,pat): 2415bd8deadSopenharmony_ci if (pat == None or pat == ''): 2425bd8deadSopenharmony_ci return '_nomatch_^' 2435bd8deadSopenharmony_ci else: 2445bd8deadSopenharmony_ci return pat 2455bd8deadSopenharmony_ci 2465bd8deadSopenharmony_ci# CGeneratorOptions - subclass of GeneratorOptions. 2475bd8deadSopenharmony_ci# 2485bd8deadSopenharmony_ci# Adds options used by COutputGenerator objects during C language header 2495bd8deadSopenharmony_ci# generation. 2505bd8deadSopenharmony_ci# 2515bd8deadSopenharmony_ci# Additional members 2525bd8deadSopenharmony_ci# prefixText - list of strings to prefix generated header with 2535bd8deadSopenharmony_ci# (usually a copyright statement + calling convention macros). 2545bd8deadSopenharmony_ci# protectFile - True if multiple inclusion protection should be 2555bd8deadSopenharmony_ci# generated (based on the filename) around the entire header. 2565bd8deadSopenharmony_ci# protectFeature - True if #ifndef..#endif protection should be 2575bd8deadSopenharmony_ci# generated around a feature interface in the header file. 2585bd8deadSopenharmony_ci# genFuncPointers - True if function pointer typedefs should be 2595bd8deadSopenharmony_ci# generated 2605bd8deadSopenharmony_ci# protectProto - Controls cpp protection around prototypes: 2615bd8deadSopenharmony_ci# False - no protection 2625bd8deadSopenharmony_ci# 'nonzero' - protectProtoStr must be defined to a nonzero value 2635bd8deadSopenharmony_ci# True - protectProtoStr must be defined 2645bd8deadSopenharmony_ci# protectProtoStr - #ifdef symbol to use around prototype 2655bd8deadSopenharmony_ci# declarations, if protected 2665bd8deadSopenharmony_ci# apicall - string to use for the function declaration prefix, 2675bd8deadSopenharmony_ci# such as APICALL on Windows. 2685bd8deadSopenharmony_ci# apientry - string to use for the calling convention macro, 2695bd8deadSopenharmony_ci# in typedefs, such as APIENTRY. 2705bd8deadSopenharmony_ci# apientryp - string to use for the calling convention macro 2715bd8deadSopenharmony_ci# in function pointer typedefs, such as APIENTRYP. 2725bd8deadSopenharmony_ciclass CGeneratorOptions(GeneratorOptions): 2735bd8deadSopenharmony_ci """Represents options during C header production from an API registry""" 2745bd8deadSopenharmony_ci def __init__(self, 2755bd8deadSopenharmony_ci filename = None, 2765bd8deadSopenharmony_ci apiname = None, 2775bd8deadSopenharmony_ci profile = None, 2785bd8deadSopenharmony_ci versions = '.*', 2795bd8deadSopenharmony_ci emitversions = '.*', 2805bd8deadSopenharmony_ci defaultExtensions = None, 2815bd8deadSopenharmony_ci addExtensions = None, 2825bd8deadSopenharmony_ci removeExtensions = None, 2835bd8deadSopenharmony_ci sortProcedure = regSortFeatures, 2845bd8deadSopenharmony_ci prefixText = "", 2855bd8deadSopenharmony_ci genFuncPointers = True, 2865bd8deadSopenharmony_ci protectFile = True, 2875bd8deadSopenharmony_ci protectFeature = True, 2885bd8deadSopenharmony_ci protectProto = True, 2895bd8deadSopenharmony_ci protectProtoStr = True, 2905bd8deadSopenharmony_ci apicall = '', 2915bd8deadSopenharmony_ci apientry = '', 2925bd8deadSopenharmony_ci apientryp = ''): 2935bd8deadSopenharmony_ci GeneratorOptions.__init__(self, filename, apiname, profile, 2945bd8deadSopenharmony_ci versions, emitversions, defaultExtensions, 2955bd8deadSopenharmony_ci addExtensions, removeExtensions, sortProcedure) 2965bd8deadSopenharmony_ci self.prefixText = prefixText 2975bd8deadSopenharmony_ci self.genFuncPointers = genFuncPointers 2985bd8deadSopenharmony_ci self.protectFile = protectFile 2995bd8deadSopenharmony_ci self.protectFeature = protectFeature 3005bd8deadSopenharmony_ci self.protectProto = protectProto 3015bd8deadSopenharmony_ci self.protectProtoStr = protectProtoStr 3025bd8deadSopenharmony_ci self.apicall = apicall 3035bd8deadSopenharmony_ci self.apientry = apientry 3045bd8deadSopenharmony_ci self.apientryp = apientryp 3055bd8deadSopenharmony_ci 3065bd8deadSopenharmony_ci# OutputGenerator - base class for generating API interfaces. 3075bd8deadSopenharmony_ci# Manages basic logic, logging, and output file control 3085bd8deadSopenharmony_ci# Derived classes actually generate formatted output. 3095bd8deadSopenharmony_ci# 3105bd8deadSopenharmony_ci# ---- methods ---- 3115bd8deadSopenharmony_ci# OutputGenerator(errFile, warnFile, diagFile) 3125bd8deadSopenharmony_ci# errFile, warnFile, diagFile - file handles to write errors, 3135bd8deadSopenharmony_ci# warnings, diagnostics to. May be None to not write. 3145bd8deadSopenharmony_ci# logMsg(level, *args) - log messages of different categories 3155bd8deadSopenharmony_ci# level - 'error', 'warn', or 'diag'. 'error' will also 3165bd8deadSopenharmony_ci# raise a UserWarning exception 3175bd8deadSopenharmony_ci# *args - print()-style arguments 3185bd8deadSopenharmony_ci# beginFile(genOpts) - start a new interface file 3195bd8deadSopenharmony_ci# genOpts - GeneratorOptions controlling what's generated and how 3205bd8deadSopenharmony_ci# endFile() - finish an interface file, closing it when done 3215bd8deadSopenharmony_ci# beginFeature(interface, emit) - write interface for a feature 3225bd8deadSopenharmony_ci# and tag generated features as having been done. 3235bd8deadSopenharmony_ci# interface - element for the <version> / <extension> to generate 3245bd8deadSopenharmony_ci# emit - actually write to the header only when True 3255bd8deadSopenharmony_ci# endFeature() - finish an interface. 3265bd8deadSopenharmony_ci# genType(typeinfo,name) - generate interface for a type 3275bd8deadSopenharmony_ci# typeinfo - TypeInfo for a type 3285bd8deadSopenharmony_ci# genEnum(enuminfo, name) - generate interface for an enum 3295bd8deadSopenharmony_ci# enuminfo - EnumInfo for an enum 3305bd8deadSopenharmony_ci# name - enum name 3315bd8deadSopenharmony_ci# genCmd(cmdinfo) - generate interface for a command 3325bd8deadSopenharmony_ci# cmdinfo - CmdInfo for a command 3335bd8deadSopenharmony_ciclass OutputGenerator: 3345bd8deadSopenharmony_ci """Generate specified API interfaces in a specific style, such as a C header""" 3355bd8deadSopenharmony_ci def __init__(self, 3365bd8deadSopenharmony_ci errFile = sys.stderr, 3375bd8deadSopenharmony_ci warnFile = sys.stderr, 3385bd8deadSopenharmony_ci diagFile = sys.stdout): 3395bd8deadSopenharmony_ci self.outFile = None 3405bd8deadSopenharmony_ci self.errFile = errFile 3415bd8deadSopenharmony_ci self.warnFile = warnFile 3425bd8deadSopenharmony_ci self.diagFile = diagFile 3435bd8deadSopenharmony_ci # Internal state 3445bd8deadSopenharmony_ci self.featureName = None 3455bd8deadSopenharmony_ci self.genOpts = None 3465bd8deadSopenharmony_ci # 3475bd8deadSopenharmony_ci # logMsg - write a message of different categories to different 3485bd8deadSopenharmony_ci # destinations. 3495bd8deadSopenharmony_ci # level - 3505bd8deadSopenharmony_ci # 'diag' (diagnostic, voluminous) 3515bd8deadSopenharmony_ci # 'warn' (warning) 3525bd8deadSopenharmony_ci # 'error' (fatal error - raises exception after logging) 3535bd8deadSopenharmony_ci # *args - print()-style arguments to direct to corresponding log 3545bd8deadSopenharmony_ci def logMsg(self, level, *args): 3555bd8deadSopenharmony_ci """Log a message at the given level. Can be ignored or log to a file""" 3565bd8deadSopenharmony_ci if (level == 'error'): 3575bd8deadSopenharmony_ci strfile = io.StringIO() 3585bd8deadSopenharmony_ci write('ERROR:', *args, file=strfile) 3595bd8deadSopenharmony_ci if (self.errFile != None): 3605bd8deadSopenharmony_ci write(strfile.getvalue(), file=self.errFile) 3615bd8deadSopenharmony_ci raise UserWarning(strfile.getvalue()) 3625bd8deadSopenharmony_ci elif (level == 'warn'): 3635bd8deadSopenharmony_ci if (self.warnFile != None): 3645bd8deadSopenharmony_ci write('WARNING:', *args, file=self.warnFile) 3655bd8deadSopenharmony_ci elif (level == 'diag'): 3665bd8deadSopenharmony_ci if (self.diagFile != None): 3675bd8deadSopenharmony_ci write('DIAG:', *args, file=self.diagFile) 3685bd8deadSopenharmony_ci else: 3695bd8deadSopenharmony_ci raise UserWarning( 3705bd8deadSopenharmony_ci '*** FATAL ERROR in Generator.logMsg: unknown level:' + level) 3715bd8deadSopenharmony_ci # 3725bd8deadSopenharmony_ci def beginFile(self, genOpts): 3735bd8deadSopenharmony_ci self.genOpts = genOpts 3745bd8deadSopenharmony_ci # 3755bd8deadSopenharmony_ci # Open specified output file. Not done in constructor since a 3765bd8deadSopenharmony_ci # Generator can be used without writing to a file. 3775bd8deadSopenharmony_ci if (self.genOpts.filename != None): 3785bd8deadSopenharmony_ci self.outFile = open(self.genOpts.filename, 'w') 3795bd8deadSopenharmony_ci else: 3805bd8deadSopenharmony_ci self.outFile = sys.stdout 3815bd8deadSopenharmony_ci def endFile(self): 3825bd8deadSopenharmony_ci self.errFile and self.errFile.flush() 3835bd8deadSopenharmony_ci self.warnFile and self.warnFile.flush() 3845bd8deadSopenharmony_ci self.diagFile and self.diagFile.flush() 3855bd8deadSopenharmony_ci self.outFile.flush() 3865bd8deadSopenharmony_ci if (self.outFile != sys.stdout and self.outFile != sys.stderr): 3875bd8deadSopenharmony_ci self.outFile.close() 3885bd8deadSopenharmony_ci self.genOpts = None 3895bd8deadSopenharmony_ci # 3905bd8deadSopenharmony_ci def beginFeature(self, interface, emit): 3915bd8deadSopenharmony_ci self.emit = emit 3925bd8deadSopenharmony_ci self.featureName = interface.get('name') 3935bd8deadSopenharmony_ci # If there's an additional 'protect' attribute in the feature, save it 3945bd8deadSopenharmony_ci self.featureExtraProtect = interface.get('protect') 3955bd8deadSopenharmony_ci def endFeature(self): 3965bd8deadSopenharmony_ci # Derived classes responsible for emitting feature 3975bd8deadSopenharmony_ci self.featureName = None 3985bd8deadSopenharmony_ci self.featureExtraProtect = None 3995bd8deadSopenharmony_ci # 4005bd8deadSopenharmony_ci # Type generation 4015bd8deadSopenharmony_ci def genType(self, typeinfo, name): 4025bd8deadSopenharmony_ci if (self.featureName == None): 4035bd8deadSopenharmony_ci raise UserWarning('Attempt to generate type', name, 4045bd8deadSopenharmony_ci 'when not in feature') 4055bd8deadSopenharmony_ci # 4065bd8deadSopenharmony_ci # Enumerant generation 4075bd8deadSopenharmony_ci def genEnum(self, enuminfo, name): 4085bd8deadSopenharmony_ci if (self.featureName == None): 4095bd8deadSopenharmony_ci raise UserWarning('Attempt to generate enum', name, 4105bd8deadSopenharmony_ci 'when not in feature') 4115bd8deadSopenharmony_ci # 4125bd8deadSopenharmony_ci # Command generation 4135bd8deadSopenharmony_ci def genCmd(self, cmd, name): 4145bd8deadSopenharmony_ci if (self.featureName == None): 4155bd8deadSopenharmony_ci raise UserWarning('Attempt to generate command', name, 4165bd8deadSopenharmony_ci 'when not in feature') 4175bd8deadSopenharmony_ci 4185bd8deadSopenharmony_ci# COutputGenerator - subclass of OutputGenerator. 4195bd8deadSopenharmony_ci# Generates C-language API interfaces. 4205bd8deadSopenharmony_ci# 4215bd8deadSopenharmony_ci# ---- methods ---- 4225bd8deadSopenharmony_ci# COutputGenerator(errFile, warnFile, diagFile) - args as for 4235bd8deadSopenharmony_ci# OutputGenerator. Defines additional internal state. 4245bd8deadSopenharmony_ci# makeCDecls(cmd) - return C prototype and function pointer typedef for a 4255bd8deadSopenharmony_ci# <command> Element, as a list of two strings 4265bd8deadSopenharmony_ci# cmd - Element for the <command> 4275bd8deadSopenharmony_ci# newline() - print a newline to the output file (utility function) 4285bd8deadSopenharmony_ci# ---- methods overriding base class ---- 4295bd8deadSopenharmony_ci# beginFile(genOpts) 4305bd8deadSopenharmony_ci# endFile() 4315bd8deadSopenharmony_ci# beginFeature(interface, emit) 4325bd8deadSopenharmony_ci# endFeature() 4335bd8deadSopenharmony_ci# genType(typeinfo,name) - generate interface for a type 4345bd8deadSopenharmony_ci# genEnum(enuminfo, name) 4355bd8deadSopenharmony_ci# genCmd(cmdinfo) 4365bd8deadSopenharmony_ciclass COutputGenerator(OutputGenerator): 4375bd8deadSopenharmony_ci """Generate specified API interfaces in a specific style, such as a C header""" 4385bd8deadSopenharmony_ci def __init__(self, 4395bd8deadSopenharmony_ci errFile = sys.stderr, 4405bd8deadSopenharmony_ci warnFile = sys.stderr, 4415bd8deadSopenharmony_ci diagFile = sys.stdout): 4425bd8deadSopenharmony_ci OutputGenerator.__init__(self, errFile, warnFile, diagFile) 4435bd8deadSopenharmony_ci # Internal state - accumulators for different inner block text 4445bd8deadSopenharmony_ci self.typeBody = '' 4455bd8deadSopenharmony_ci self.enumBody = '' 4465bd8deadSopenharmony_ci self.cmdBody = '' 4475bd8deadSopenharmony_ci # 4485bd8deadSopenharmony_ci # makeCDecls - return C prototype and function pointer typedef for a 4495bd8deadSopenharmony_ci # command, as a two-element list of strings. 4505bd8deadSopenharmony_ci # cmd - Element containing a <command> tag 4515bd8deadSopenharmony_ci def makeCDecls(self, cmd): 4525bd8deadSopenharmony_ci """Generate C function pointer typedef for <command> Element""" 4535bd8deadSopenharmony_ci proto = cmd.find('proto') 4545bd8deadSopenharmony_ci params = cmd.findall('param') 4555bd8deadSopenharmony_ci # Begin accumulating prototype and typedef strings 4565bd8deadSopenharmony_ci pdecl = self.genOpts.apicall 4575bd8deadSopenharmony_ci tdecl = 'typedef ' 4585bd8deadSopenharmony_ci # 4595bd8deadSopenharmony_ci # Insert the function return type/name. 4605bd8deadSopenharmony_ci # For prototypes, add APIENTRY macro before the name 4615bd8deadSopenharmony_ci # For typedefs, add (APIENTRYP <name>) around the name and 4625bd8deadSopenharmony_ci # use the PFNGLCMDNAMEPROC nameng convention. 4635bd8deadSopenharmony_ci # Done by walking the tree for <proto> element by element. 4645bd8deadSopenharmony_ci # lxml.etree has elem.text followed by (elem[i], elem[i].tail) 4655bd8deadSopenharmony_ci # for each child element and any following text 4665bd8deadSopenharmony_ci # Leading text 4675bd8deadSopenharmony_ci pdecl += noneStr(proto.text) 4685bd8deadSopenharmony_ci tdecl += noneStr(proto.text) 4695bd8deadSopenharmony_ci # For each child element, if it's a <name> wrap in appropriate 4705bd8deadSopenharmony_ci # declaration. Otherwise append its contents and tail contents. 4715bd8deadSopenharmony_ci for elem in proto: 4725bd8deadSopenharmony_ci text = noneStr(elem.text) 4735bd8deadSopenharmony_ci tail = noneStr(elem.tail) 4745bd8deadSopenharmony_ci if (elem.tag == 'name'): 4755bd8deadSopenharmony_ci pdecl += self.genOpts.apientry + text + tail 4765bd8deadSopenharmony_ci tdecl += '(' + self.genOpts.apientryp + 'PFN' + text.upper() + 'PROC' + tail + ')' 4775bd8deadSopenharmony_ci else: 4785bd8deadSopenharmony_ci pdecl += text + tail 4795bd8deadSopenharmony_ci tdecl += text + tail 4805bd8deadSopenharmony_ci # Now add the parameter declaration list, which is identical 4815bd8deadSopenharmony_ci # for prototypes and typedefs. Concatenate all the text from 4825bd8deadSopenharmony_ci # a <param> node without the tags. No tree walking required 4835bd8deadSopenharmony_ci # since all tags are ignored. 4845bd8deadSopenharmony_ci n = len(params) 4855bd8deadSopenharmony_ci paramdecl = ' (' 4865bd8deadSopenharmony_ci if n > 0: 4875bd8deadSopenharmony_ci for i in range(0,n): 4885bd8deadSopenharmony_ci paramdecl += ''.join([t for t in params[i].itertext()]) 4895bd8deadSopenharmony_ci if (i < n - 1): 4905bd8deadSopenharmony_ci paramdecl += ', ' 4915bd8deadSopenharmony_ci else: 4925bd8deadSopenharmony_ci paramdecl += 'void' 4935bd8deadSopenharmony_ci paramdecl += ');\n'; 4945bd8deadSopenharmony_ci return [ pdecl + paramdecl, tdecl + paramdecl ] 4955bd8deadSopenharmony_ci # 4965bd8deadSopenharmony_ci def newline(self): 4975bd8deadSopenharmony_ci write('', file=self.outFile) 4985bd8deadSopenharmony_ci # 4995bd8deadSopenharmony_ci def beginFile(self, genOpts): 5005bd8deadSopenharmony_ci OutputGenerator.beginFile(self, genOpts) 5015bd8deadSopenharmony_ci # C-specific 5025bd8deadSopenharmony_ci # 5035bd8deadSopenharmony_ci # Multiple inclusion protection & C++ wrappers. 5045bd8deadSopenharmony_ci if (genOpts.protectFile and self.genOpts.filename): 5055bd8deadSopenharmony_ci headerSym = '__' + self.genOpts.apiname + '_' + re.sub('\.h', '_h_', os.path.basename(self.genOpts.filename)) 5065bd8deadSopenharmony_ci write('#ifndef', headerSym, file=self.outFile) 5075bd8deadSopenharmony_ci write('#define', headerSym, '1', file=self.outFile) 5085bd8deadSopenharmony_ci self.newline() 5095bd8deadSopenharmony_ci write('#ifdef __cplusplus', file=self.outFile) 5105bd8deadSopenharmony_ci write('extern "C" {', file=self.outFile) 5115bd8deadSopenharmony_ci write('#endif', file=self.outFile) 5125bd8deadSopenharmony_ci self.newline() 5135bd8deadSopenharmony_ci # 5145bd8deadSopenharmony_ci # User-supplied prefix text, if any (list of strings) 5155bd8deadSopenharmony_ci if (genOpts.prefixText): 5165bd8deadSopenharmony_ci for s in genOpts.prefixText: 5175bd8deadSopenharmony_ci write(s, file=self.outFile) 5185bd8deadSopenharmony_ci # 5195bd8deadSopenharmony_ci # Some boilerplate describing what was generated - this 5205bd8deadSopenharmony_ci # will probably be removed later since the extensions 5215bd8deadSopenharmony_ci # pattern may be very long. 5225bd8deadSopenharmony_ci write('/* Generated C header for:', file=self.outFile) 5235bd8deadSopenharmony_ci write(' * API:', genOpts.apiname, file=self.outFile) 5245bd8deadSopenharmony_ci if (genOpts.profile): 5255bd8deadSopenharmony_ci write(' * Profile:', genOpts.profile, file=self.outFile) 5265bd8deadSopenharmony_ci write(' * Versions considered:', genOpts.versions, file=self.outFile) 5275bd8deadSopenharmony_ci write(' * Versions emitted:', genOpts.emitversions, file=self.outFile) 5285bd8deadSopenharmony_ci write(' * Default extensions included:', genOpts.defaultExtensions, file=self.outFile) 5295bd8deadSopenharmony_ci write(' * Additional extensions included:', genOpts.addExtensions, file=self.outFile) 5305bd8deadSopenharmony_ci write(' * Extensions removed:', genOpts.removeExtensions, file=self.outFile) 5315bd8deadSopenharmony_ci write(' */', file=self.outFile) 5325bd8deadSopenharmony_ci def endFile(self): 5335bd8deadSopenharmony_ci # C-specific 5345bd8deadSopenharmony_ci # Finish C++ wrapper and multiple inclusion protection 5355bd8deadSopenharmony_ci self.newline() 5365bd8deadSopenharmony_ci write('#ifdef __cplusplus', file=self.outFile) 5375bd8deadSopenharmony_ci write('}', file=self.outFile) 5385bd8deadSopenharmony_ci write('#endif', file=self.outFile) 5395bd8deadSopenharmony_ci if (self.genOpts.protectFile and self.genOpts.filename): 5405bd8deadSopenharmony_ci self.newline() 5415bd8deadSopenharmony_ci write('#endif', file=self.outFile) 5425bd8deadSopenharmony_ci # Finish processing in superclass 5435bd8deadSopenharmony_ci OutputGenerator.endFile(self) 5445bd8deadSopenharmony_ci def beginFeature(self, interface, emit): 5455bd8deadSopenharmony_ci # Start processing in superclass 5465bd8deadSopenharmony_ci OutputGenerator.beginFeature(self, interface, emit) 5475bd8deadSopenharmony_ci # C-specific 5485bd8deadSopenharmony_ci # Accumulate types, enums, function pointer typedefs, end function 5495bd8deadSopenharmony_ci # prototypes separately for this feature. They're only printed in 5505bd8deadSopenharmony_ci # endFeature(). 5515bd8deadSopenharmony_ci self.typeBody = '' 5525bd8deadSopenharmony_ci self.enumBody = '' 5535bd8deadSopenharmony_ci self.cmdPointerBody = '' 5545bd8deadSopenharmony_ci self.cmdBody = '' 5555bd8deadSopenharmony_ci def endFeature(self): 5565bd8deadSopenharmony_ci # C-specific 5575bd8deadSopenharmony_ci # Actually write the interface to the output file. 5585bd8deadSopenharmony_ci if (self.emit): 5595bd8deadSopenharmony_ci self.newline() 5605bd8deadSopenharmony_ci if (self.genOpts.protectFeature): 5615bd8deadSopenharmony_ci write('#ifndef', self.featureName, file=self.outFile) 5625bd8deadSopenharmony_ci write('#define', self.featureName, '1', file=self.outFile) 5635bd8deadSopenharmony_ci if (self.typeBody != ''): 5645bd8deadSopenharmony_ci write(self.typeBody, end='', file=self.outFile) 5655bd8deadSopenharmony_ci # 5665bd8deadSopenharmony_ci # Don't add additional protection for derived type declarations, 5675bd8deadSopenharmony_ci # which may be needed by other features later on. 5685bd8deadSopenharmony_ci if (self.featureExtraProtect != None): 5695bd8deadSopenharmony_ci write('#ifdef', self.featureExtraProtect, file=self.outFile) 5705bd8deadSopenharmony_ci if (self.enumBody != ''): 5715bd8deadSopenharmony_ci write(self.enumBody, end='', file=self.outFile) 5725bd8deadSopenharmony_ci if (self.genOpts.genFuncPointers and self.cmdPointerBody != ''): 5735bd8deadSopenharmony_ci write(self.cmdPointerBody, end='', file=self.outFile) 5745bd8deadSopenharmony_ci if (self.cmdBody != ''): 5755bd8deadSopenharmony_ci if (self.genOpts.protectProto == True): 5765bd8deadSopenharmony_ci prefix = '#ifdef ' + self.genOpts.protectProtoStr + '\n' 5775bd8deadSopenharmony_ci suffix = '#endif\n' 5785bd8deadSopenharmony_ci elif (self.genOpts.protectProto == 'nonzero'): 5795bd8deadSopenharmony_ci prefix = '#if ' + self.genOpts.protectProtoStr + '\n' 5805bd8deadSopenharmony_ci suffix = '#endif\n' 5815bd8deadSopenharmony_ci elif (self.genOpts.protectProto == False): 5825bd8deadSopenharmony_ci prefix = '' 5835bd8deadSopenharmony_ci suffix = '' 5845bd8deadSopenharmony_ci else: 5855bd8deadSopenharmony_ci self.gen.logMsg('warn', 5865bd8deadSopenharmony_ci '*** Unrecognized value for protectProto:', 5875bd8deadSopenharmony_ci self.genOpts.protectProto, 5885bd8deadSopenharmony_ci 'not generating prototype wrappers') 5895bd8deadSopenharmony_ci prefix = '' 5905bd8deadSopenharmony_ci suffix = '' 5915bd8deadSopenharmony_ci 5925bd8deadSopenharmony_ci write(prefix + self.cmdBody + suffix, end='', file=self.outFile) 5935bd8deadSopenharmony_ci if (self.featureExtraProtect != None): 5945bd8deadSopenharmony_ci write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) 5955bd8deadSopenharmony_ci if (self.genOpts.protectFeature): 5965bd8deadSopenharmony_ci write('#endif /*', self.featureName, '*/', file=self.outFile) 5975bd8deadSopenharmony_ci # Finish processing in superclass 5985bd8deadSopenharmony_ci OutputGenerator.endFeature(self) 5995bd8deadSopenharmony_ci # 6005bd8deadSopenharmony_ci # Type generation 6015bd8deadSopenharmony_ci def genType(self, typeinfo, name): 6025bd8deadSopenharmony_ci OutputGenerator.genType(self, typeinfo, name) 6035bd8deadSopenharmony_ci # 6045bd8deadSopenharmony_ci # Replace <apientry /> tags with an APIENTRY-style string 6055bd8deadSopenharmony_ci # (from self.genOpts). Copy other text through unchanged. 6065bd8deadSopenharmony_ci # If the resulting text is an empty string, don't emit it. 6075bd8deadSopenharmony_ci typeElem = typeinfo.elem 6085bd8deadSopenharmony_ci s = noneStr(typeElem.text) 6095bd8deadSopenharmony_ci for elem in typeElem: 6105bd8deadSopenharmony_ci if (elem.tag == 'apientry'): 6115bd8deadSopenharmony_ci s += self.genOpts.apientry + noneStr(elem.tail) 6125bd8deadSopenharmony_ci else: 6135bd8deadSopenharmony_ci s += noneStr(elem.text) + noneStr(elem.tail) 6145bd8deadSopenharmony_ci if (len(s) > 0): 6155bd8deadSopenharmony_ci self.typeBody += s + '\n' 6165bd8deadSopenharmony_ci # 6175bd8deadSopenharmony_ci # Enumerant generation 6185bd8deadSopenharmony_ci def genEnum(self, enuminfo, name): 6195bd8deadSopenharmony_ci OutputGenerator.genEnum(self, enuminfo, name) 6205bd8deadSopenharmony_ci # 6215bd8deadSopenharmony_ci # EnumInfo.type is a C value suffix (e.g. u, ull) 6225bd8deadSopenharmony_ci self.enumBody += '#define ' + name.ljust(33) + ' ' + enuminfo.elem.get('value') 6235bd8deadSopenharmony_ci # 6245bd8deadSopenharmony_ci # Handle non-integer 'type' fields by using it as the C value suffix 6255bd8deadSopenharmony_ci t = enuminfo.elem.get('type') 6265bd8deadSopenharmony_ci if (t != '' and t != 'i'): 6275bd8deadSopenharmony_ci self.enumBody += enuminfo.type 6285bd8deadSopenharmony_ci self.enumBody += '\n' 6295bd8deadSopenharmony_ci # 6305bd8deadSopenharmony_ci # Command generation 6315bd8deadSopenharmony_ci def genCmd(self, cmdinfo, name): 6325bd8deadSopenharmony_ci OutputGenerator.genCmd(self, cmdinfo, name) 6335bd8deadSopenharmony_ci # 6345bd8deadSopenharmony_ci decls = self.makeCDecls(cmdinfo.elem) 6355bd8deadSopenharmony_ci self.cmdBody += decls[0] 6365bd8deadSopenharmony_ci if (self.genOpts.genFuncPointers): 6375bd8deadSopenharmony_ci self.cmdPointerBody += decls[1] 6385bd8deadSopenharmony_ci 6395bd8deadSopenharmony_ci# Registry - object representing an API registry, loaded from an XML file 6405bd8deadSopenharmony_ci# Members 6415bd8deadSopenharmony_ci# tree - ElementTree containing the root <registry> 6425bd8deadSopenharmony_ci# typedict - dictionary of TypeInfo objects keyed by type name 6435bd8deadSopenharmony_ci# groupdict - dictionary of GroupInfo objects keyed by group name 6445bd8deadSopenharmony_ci# enumdict - dictionary of EnumInfo objects keyed by enum name 6455bd8deadSopenharmony_ci# cmddict - dictionary of CmdInfo objects keyed by command name 6465bd8deadSopenharmony_ci# apidict - dictionary of <api> Elements keyed by API name 6475bd8deadSopenharmony_ci# extensions - list of <extension> Elements 6485bd8deadSopenharmony_ci# extdict - dictionary of <extension> Elements keyed by extension name 6495bd8deadSopenharmony_ci# gen - OutputGenerator object used to write headers / messages 6505bd8deadSopenharmony_ci# genOpts - GeneratorOptions object used to control which 6515bd8deadSopenharmony_ci# fetures to write and how to format them 6525bd8deadSopenharmony_ci# emitFeatures - True to actually emit features for a version / extension, 6535bd8deadSopenharmony_ci# or False to just treat them as emitted 6545bd8deadSopenharmony_ci# Public methods 6555bd8deadSopenharmony_ci# loadElementTree(etree) - load registry from specified ElementTree 6565bd8deadSopenharmony_ci# loadFile(filename) - load registry from XML file 6575bd8deadSopenharmony_ci# setGenerator(gen) - OutputGenerator to use 6585bd8deadSopenharmony_ci# parseTree() - parse the registry once loaded & create dictionaries 6595bd8deadSopenharmony_ci# dumpReg(maxlen, filehandle) - diagnostic to dump the dictionaries 6605bd8deadSopenharmony_ci# to specified file handle (default stdout). Truncates type / 6615bd8deadSopenharmony_ci# enum / command elements to maxlen characters (default 80) 6625bd8deadSopenharmony_ci# generator(g) - specify the output generator object 6635bd8deadSopenharmony_ci# apiGen(apiname, genOpts) - generate API headers for the API type 6645bd8deadSopenharmony_ci# and profile specified in genOpts, but only for the versions and 6655bd8deadSopenharmony_ci# extensions specified there. 6665bd8deadSopenharmony_ci# apiReset() - call between calls to apiGen() to reset internal state 6675bd8deadSopenharmony_ci# validateGroups() - call to verify that each <proto> or <param> 6685bd8deadSopenharmony_ci# with a 'group' attribute matches an actual existing group. 6695bd8deadSopenharmony_ci# Private methods 6705bd8deadSopenharmony_ci# addElementInfo(elem,info,infoName,dictionary) - add feature info to dict 6715bd8deadSopenharmony_ci# lookupElementInfo(fname,dictionary) - lookup feature info in dict 6725bd8deadSopenharmony_ciclass Registry: 6735bd8deadSopenharmony_ci """Represents an API registry loaded from XML""" 6745bd8deadSopenharmony_ci def __init__(self): 6755bd8deadSopenharmony_ci self.tree = None 6765bd8deadSopenharmony_ci self.typedict = {} 6775bd8deadSopenharmony_ci self.groupdict = {} 6785bd8deadSopenharmony_ci self.enumdict = {} 6795bd8deadSopenharmony_ci self.cmddict = {} 6805bd8deadSopenharmony_ci self.apidict = {} 6815bd8deadSopenharmony_ci self.extensions = [] 6825bd8deadSopenharmony_ci self.extdict = {} 6835bd8deadSopenharmony_ci # A default output generator, so commands prior to apiGen can report 6845bd8deadSopenharmony_ci # errors via the generator object. 6855bd8deadSopenharmony_ci self.gen = OutputGenerator() 6865bd8deadSopenharmony_ci self.genOpts = None 6875bd8deadSopenharmony_ci self.emitFeatures = False 6885bd8deadSopenharmony_ci def loadElementTree(self, tree): 6895bd8deadSopenharmony_ci """Load ElementTree into a Registry object and parse it""" 6905bd8deadSopenharmony_ci self.tree = tree 6915bd8deadSopenharmony_ci self.parseTree() 6925bd8deadSopenharmony_ci def loadFile(self, file): 6935bd8deadSopenharmony_ci """Load an API registry XML file into a Registry object and parse it""" 6945bd8deadSopenharmony_ci self.tree = etree.parse(file) 6955bd8deadSopenharmony_ci self.parseTree() 6965bd8deadSopenharmony_ci def setGenerator(self, gen): 6975bd8deadSopenharmony_ci """Specify output generator object. None restores the default generator""" 6985bd8deadSopenharmony_ci self.gen = gen 6995bd8deadSopenharmony_ci # addElementInfo - add information about an element to the 7005bd8deadSopenharmony_ci # corresponding dictionary 7015bd8deadSopenharmony_ci # elem - <type>/<group>/<enum>/<command>/<feature>/<extension> Element 7025bd8deadSopenharmony_ci # info - corresponding {Type|Group|Enum|Cmd|Feature}Info object 7035bd8deadSopenharmony_ci # infoName - 'type' / 'group' / 'enum' / 'command' / 'feature' / 'extension' 7045bd8deadSopenharmony_ci # dictionary - self.{type|group|enum|cmd|api|ext}dict 7055bd8deadSopenharmony_ci # If the Element has an 'api' attribute, the dictionary key is the 7065bd8deadSopenharmony_ci # tuple (name,api). If not, the key is the name. 'name' is an 7075bd8deadSopenharmony_ci # attribute of the Element 7085bd8deadSopenharmony_ci def addElementInfo(self, elem, info, infoName, dictionary): 7095bd8deadSopenharmony_ci if ('api' in elem.attrib): 7105bd8deadSopenharmony_ci key = (elem.get('name'),elem.get('api')) 7115bd8deadSopenharmony_ci else: 7125bd8deadSopenharmony_ci key = elem.get('name') 7135bd8deadSopenharmony_ci if key in dictionary: 7145bd8deadSopenharmony_ci self.gen.logMsg('warn', '*** Attempt to redefine', 7155bd8deadSopenharmony_ci infoName, 'with key:', key) 7165bd8deadSopenharmony_ci else: 7175bd8deadSopenharmony_ci dictionary[key] = info 7185bd8deadSopenharmony_ci # 7195bd8deadSopenharmony_ci # lookupElementInfo - find a {Type|Enum|Cmd}Info object by name. 7205bd8deadSopenharmony_ci # If an object qualified by API name exists, use that. 7215bd8deadSopenharmony_ci # fname - name of type / enum / command 7225bd8deadSopenharmony_ci # dictionary - self.{type|enum|cmd}dict 7235bd8deadSopenharmony_ci def lookupElementInfo(self, fname, dictionary): 7245bd8deadSopenharmony_ci key = (fname, self.genOpts.apiname) 7255bd8deadSopenharmony_ci if (key in dictionary): 7265bd8deadSopenharmony_ci # self.gen.logMsg('diag', 'Found API-specific element for feature', fname) 7275bd8deadSopenharmony_ci return dictionary[key] 7285bd8deadSopenharmony_ci elif (fname in dictionary): 7295bd8deadSopenharmony_ci # self.gen.logMsg('diag', 'Found generic element for feature', fname) 7305bd8deadSopenharmony_ci return dictionary[fname] 7315bd8deadSopenharmony_ci else: 7325bd8deadSopenharmony_ci return None 7335bd8deadSopenharmony_ci def parseTree(self): 7345bd8deadSopenharmony_ci """Parse the registry Element, once created""" 7355bd8deadSopenharmony_ci # This must be the Element for the root <registry> 7365bd8deadSopenharmony_ci self.reg = self.tree.getroot() 7375bd8deadSopenharmony_ci # 7385bd8deadSopenharmony_ci # Create dictionary of registry types from toplevel <types> tags 7395bd8deadSopenharmony_ci # and add 'name' attribute to each <type> tag (where missing) 7405bd8deadSopenharmony_ci # based on its <name> element. 7415bd8deadSopenharmony_ci # 7425bd8deadSopenharmony_ci # There's usually one <types> block; more are OK 7435bd8deadSopenharmony_ci # Required <type> attributes: 'name' or nested <name> tag contents 7445bd8deadSopenharmony_ci self.typedict = {} 7455bd8deadSopenharmony_ci for type in self.reg.findall('types/type'): 7465bd8deadSopenharmony_ci # If the <type> doesn't already have a 'name' attribute, set 7475bd8deadSopenharmony_ci # it from contents of its <name> tag. 7485bd8deadSopenharmony_ci if (type.get('name') == None): 7495bd8deadSopenharmony_ci type.attrib['name'] = type.find('name').text 7505bd8deadSopenharmony_ci self.addElementInfo(type, TypeInfo(type), 'type', self.typedict) 7515bd8deadSopenharmony_ci # 7525bd8deadSopenharmony_ci # Create dictionary of registry groups from toplevel <groups> tags. 7535bd8deadSopenharmony_ci # 7545bd8deadSopenharmony_ci # There's usually one <groups> block; more are OK. 7555bd8deadSopenharmony_ci # Required <group> attributes: 'name' 7565bd8deadSopenharmony_ci self.groupdict = {} 7575bd8deadSopenharmony_ci for group in self.reg.findall('groups/group'): 7585bd8deadSopenharmony_ci self.addElementInfo(group, GroupInfo(group), 'group', self.groupdict) 7595bd8deadSopenharmony_ci # 7605bd8deadSopenharmony_ci # Create dictionary of registry enums from toplevel <enums> tags 7615bd8deadSopenharmony_ci # 7625bd8deadSopenharmony_ci # There are usually many <enums> tags in different namespaces, but 7635bd8deadSopenharmony_ci # these are functional namespaces of the values, while the actual 7645bd8deadSopenharmony_ci # enum names all share the dictionary. 7655bd8deadSopenharmony_ci # Required <enums> attributes: 'name', 'value' 7665bd8deadSopenharmony_ci self.enumdict = {} 7675bd8deadSopenharmony_ci for enum in self.reg.findall('enums/enum'): 7685bd8deadSopenharmony_ci self.addElementInfo(enum, EnumInfo(enum), 'enum', self.enumdict) 7695bd8deadSopenharmony_ci # 7705bd8deadSopenharmony_ci # Create dictionary of registry commands from <command> tags 7715bd8deadSopenharmony_ci # and add 'name' attribute to each <command> tag (where missing) 7725bd8deadSopenharmony_ci # based on its <proto><name> element. 7735bd8deadSopenharmony_ci # 7745bd8deadSopenharmony_ci # There's usually only one <commands> block; more are OK. 7755bd8deadSopenharmony_ci # Required <command> attributes: 'name' or <proto><name> tag contents 7765bd8deadSopenharmony_ci self.cmddict = {} 7775bd8deadSopenharmony_ci for cmd in self.reg.findall('commands/command'): 7785bd8deadSopenharmony_ci # If the <command> doesn't already have a 'name' attribute, set 7795bd8deadSopenharmony_ci # it from contents of its <proto><name> tag. 7805bd8deadSopenharmony_ci if (cmd.get('name') == None): 7815bd8deadSopenharmony_ci cmd.attrib['name'] = cmd.find('proto/name').text 7825bd8deadSopenharmony_ci ci = CmdInfo(cmd) 7835bd8deadSopenharmony_ci self.addElementInfo(cmd, ci, 'command', self.cmddict) 7845bd8deadSopenharmony_ci # 7855bd8deadSopenharmony_ci # Create dictionaries of API and extension interfaces 7865bd8deadSopenharmony_ci # from toplevel <api> and <extension> tags. 7875bd8deadSopenharmony_ci # 7885bd8deadSopenharmony_ci self.apidict = {} 7895bd8deadSopenharmony_ci for feature in self.reg.findall('feature'): 7905bd8deadSopenharmony_ci ai = FeatureInfo(feature) 7915bd8deadSopenharmony_ci self.addElementInfo(feature, ai, 'feature', self.apidict) 7925bd8deadSopenharmony_ci self.extensions = self.reg.findall('extensions/extension') 7935bd8deadSopenharmony_ci self.extdict = {} 7945bd8deadSopenharmony_ci for feature in self.extensions: 7955bd8deadSopenharmony_ci ei = FeatureInfo(feature) 7965bd8deadSopenharmony_ci self.addElementInfo(feature, ei, 'extension', self.extdict) 7975bd8deadSopenharmony_ci def dumpReg(self, maxlen = 40, filehandle = sys.stdout): 7985bd8deadSopenharmony_ci """Dump all the dictionaries constructed from the Registry object""" 7995bd8deadSopenharmony_ci write('***************************************', file=filehandle) 8005bd8deadSopenharmony_ci write(' ** Dumping Registry contents **', file=filehandle) 8015bd8deadSopenharmony_ci write('***************************************', file=filehandle) 8025bd8deadSopenharmony_ci write('// Types', file=filehandle) 8035bd8deadSopenharmony_ci for name in self.typedict: 8045bd8deadSopenharmony_ci tobj = self.typedict[name] 8055bd8deadSopenharmony_ci write(' Type', name, '->', etree.tostring(tobj.elem)[0:maxlen], file=filehandle) 8065bd8deadSopenharmony_ci write('// Groups', file=filehandle) 8075bd8deadSopenharmony_ci for name in self.groupdict: 8085bd8deadSopenharmony_ci gobj = self.groupdict[name] 8095bd8deadSopenharmony_ci write(' Group', name, '->', etree.tostring(gobj.elem)[0:maxlen], file=filehandle) 8105bd8deadSopenharmony_ci write('// Enums', file=filehandle) 8115bd8deadSopenharmony_ci for name in self.enumdict: 8125bd8deadSopenharmony_ci eobj = self.enumdict[name] 8135bd8deadSopenharmony_ci write(' Enum', name, '->', etree.tostring(eobj.elem)[0:maxlen], file=filehandle) 8145bd8deadSopenharmony_ci write('// Commands', file=filehandle) 8155bd8deadSopenharmony_ci for name in self.cmddict: 8165bd8deadSopenharmony_ci cobj = self.cmddict[name] 8175bd8deadSopenharmony_ci write(' Command', name, '->', etree.tostring(cobj.elem)[0:maxlen], file=filehandle) 8185bd8deadSopenharmony_ci write('// APIs', file=filehandle) 8195bd8deadSopenharmony_ci for key in self.apidict: 8205bd8deadSopenharmony_ci write(' API Version ', key, '->', 8215bd8deadSopenharmony_ci etree.tostring(self.apidict[key].elem)[0:maxlen], file=filehandle) 8225bd8deadSopenharmony_ci write('// Extensions', file=filehandle) 8235bd8deadSopenharmony_ci for key in self.extdict: 8245bd8deadSopenharmony_ci write(' Extension', key, '->', 8255bd8deadSopenharmony_ci etree.tostring(self.extdict[key].elem)[0:maxlen], file=filehandle) 8265bd8deadSopenharmony_ci # write('***************************************', file=filehandle) 8275bd8deadSopenharmony_ci # write(' ** Dumping XML ElementTree **', file=filehandle) 8285bd8deadSopenharmony_ci # write('***************************************', file=filehandle) 8295bd8deadSopenharmony_ci # write(etree.tostring(self.tree.getroot(),pretty_print=True), file=filehandle) 8305bd8deadSopenharmony_ci # 8315bd8deadSopenharmony_ci # typename - name of type 8325bd8deadSopenharmony_ci # required - boolean (to tag features as required or not) 8335bd8deadSopenharmony_ci def markTypeRequired(self, typename, required): 8345bd8deadSopenharmony_ci """Require (along with its dependencies) or remove (but not its dependencies) a type""" 8355bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** tagging type:', typename, '-> required =', required) 8365bd8deadSopenharmony_ci # Get TypeInfo object for <type> tag corresponding to typename 8375bd8deadSopenharmony_ci type = self.lookupElementInfo(typename, self.typedict) 8385bd8deadSopenharmony_ci if (type != None): 8395bd8deadSopenharmony_ci # Tag required type dependencies as required. 8405bd8deadSopenharmony_ci # This DOES NOT un-tag dependencies in a <remove> tag. 8415bd8deadSopenharmony_ci # See comments in markRequired() below for the reason. 8425bd8deadSopenharmony_ci if (required and ('requires' in type.elem.attrib)): 8435bd8deadSopenharmony_ci depType = type.elem.get('requires') 8445bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Generating dependent type', 8455bd8deadSopenharmony_ci depType, 'for type', typename) 8465bd8deadSopenharmony_ci self.markTypeRequired(depType, required) 8475bd8deadSopenharmony_ci type.required = required 8485bd8deadSopenharmony_ci else: 8495bd8deadSopenharmony_ci self.gen.logMsg('warn', '*** type:', typename , 'IS NOT DEFINED') 8505bd8deadSopenharmony_ci # 8515bd8deadSopenharmony_ci # features - Element for <require> or <remove> tag 8525bd8deadSopenharmony_ci # required - boolean (to tag features as required or not) 8535bd8deadSopenharmony_ci def markRequired(self, features, required): 8545bd8deadSopenharmony_ci """Require or remove features specified in the Element""" 8555bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** markRequired (features = <too long to print>, required =', required, ')') 8565bd8deadSopenharmony_ci # Loop over types, enums, and commands in the tag 8575bd8deadSopenharmony_ci # @@ It would be possible to respect 'api' and 'profile' attributes 8585bd8deadSopenharmony_ci # in individual features, but that's not done yet. 8595bd8deadSopenharmony_ci for typeElem in features.findall('type'): 8605bd8deadSopenharmony_ci self.markTypeRequired(typeElem.get('name'), required) 8615bd8deadSopenharmony_ci for enumElem in features.findall('enum'): 8625bd8deadSopenharmony_ci name = enumElem.get('name') 8635bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** tagging enum:', name, '-> required =', required) 8645bd8deadSopenharmony_ci enum = self.lookupElementInfo(name, self.enumdict) 8655bd8deadSopenharmony_ci if (enum != None): 8665bd8deadSopenharmony_ci enum.required = required 8675bd8deadSopenharmony_ci else: 8685bd8deadSopenharmony_ci self.gen.logMsg('warn', '*** enum:', name , 'IS NOT DEFINED') 8695bd8deadSopenharmony_ci for cmdElem in features.findall('command'): 8705bd8deadSopenharmony_ci name = cmdElem.get('name') 8715bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** tagging command:', name, '-> required =', required) 8725bd8deadSopenharmony_ci cmd = self.lookupElementInfo(name, self.cmddict) 8735bd8deadSopenharmony_ci if (cmd != None): 8745bd8deadSopenharmony_ci cmd.required = required 8755bd8deadSopenharmony_ci # Tag all parameter types of this command as required. 8765bd8deadSopenharmony_ci # This DOES NOT remove types of commands in a <remove> 8775bd8deadSopenharmony_ci # tag, because many other commands may use the same type. 8785bd8deadSopenharmony_ci # We could be more clever and reference count types, 8795bd8deadSopenharmony_ci # instead of using a boolean. 8805bd8deadSopenharmony_ci if (required): 8815bd8deadSopenharmony_ci # Look for <ptype> in entire <command> tree, 8825bd8deadSopenharmony_ci # not just immediate children 8835bd8deadSopenharmony_ci for ptype in cmd.elem.findall('.//ptype'): 8845bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** markRequired: command implicitly requires dependent type', ptype.text) 8855bd8deadSopenharmony_ci self.markTypeRequired(ptype.text, required) 8865bd8deadSopenharmony_ci else: 8875bd8deadSopenharmony_ci self.gen.logMsg('warn', '*** command:', name, 'IS NOT DEFINED') 8885bd8deadSopenharmony_ci # 8895bd8deadSopenharmony_ci # interface - Element for <version> or <extension>, containing 8905bd8deadSopenharmony_ci # <require> and <remove> tags 8915bd8deadSopenharmony_ci # api - string specifying API name being generated 8925bd8deadSopenharmony_ci # profile - string specifying API profile being generated 8935bd8deadSopenharmony_ci def requireAndRemoveFeatures(self, interface, api, profile): 8945bd8deadSopenharmony_ci """Process <recquire> and <remove> tags for a <version> or <extension>""" 8955bd8deadSopenharmony_ci # <require> marks things that are required by this version/profile 8965bd8deadSopenharmony_ci for feature in interface.findall('require'): 8975bd8deadSopenharmony_ci if (matchAPIProfile(api, profile, feature)): 8985bd8deadSopenharmony_ci self.markRequired(feature,True) 8995bd8deadSopenharmony_ci # <remove> marks things that are removed by this version/profile 9005bd8deadSopenharmony_ci for feature in interface.findall('remove'): 9015bd8deadSopenharmony_ci if (matchAPIProfile(api, profile, feature)): 9025bd8deadSopenharmony_ci self.markRequired(feature,False) 9035bd8deadSopenharmony_ci # 9045bd8deadSopenharmony_ci # generateFeature - generate a single type / enum / command, 9055bd8deadSopenharmony_ci # and all its dependencies as needed. 9065bd8deadSopenharmony_ci # fname - name of feature (<type>/<enum>/<command> 9075bd8deadSopenharmony_ci # ftype - type of feature, 'type' | 'enum' | 'command' 9085bd8deadSopenharmony_ci # dictionary - of *Info objects - self.{type|enum|cmd}dict 9095bd8deadSopenharmony_ci # genProc - bound function pointer for self.gen.gen{Type|Enum|Cmd} 9105bd8deadSopenharmony_ci def generateFeature(self, fname, ftype, dictionary, genProc): 9115bd8deadSopenharmony_ci f = self.lookupElementInfo(fname, dictionary) 9125bd8deadSopenharmony_ci if (f == None): 9135bd8deadSopenharmony_ci # No such feature. This is an error, but reported earlier 9145bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** No entry found for feature', fname, 9155bd8deadSopenharmony_ci 'returning!') 9165bd8deadSopenharmony_ci return 9175bd8deadSopenharmony_ci # 9185bd8deadSopenharmony_ci # If feature isn't required, or has already been declared, return 9195bd8deadSopenharmony_ci if (not f.required): 9205bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(not required)') 9215bd8deadSopenharmony_ci return 9225bd8deadSopenharmony_ci if (f.declared): 9235bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Skipping', ftype, fname, '(already declared)') 9245bd8deadSopenharmony_ci return 9255bd8deadSopenharmony_ci # 9265bd8deadSopenharmony_ci # Pull in dependent type declaration(s) of the feature. 9275bd8deadSopenharmony_ci # For types, there may be one in the 'required' attribute of the element 9285bd8deadSopenharmony_ci # For commands, there may be many in <ptype> tags within the element 9295bd8deadSopenharmony_ci # For enums, no dependencies are allowed (though perhasps if you 9305bd8deadSopenharmony_ci # have a uint64 enum, it should require GLuint64) 9315bd8deadSopenharmony_ci if (ftype == 'type'): 9325bd8deadSopenharmony_ci if ('requires' in f.elem.attrib): 9335bd8deadSopenharmony_ci depname = f.elem.get('requires') 9345bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Generating required dependent type', 9355bd8deadSopenharmony_ci depname) 9365bd8deadSopenharmony_ci self.generateFeature(depname, 'type', self.typedict, 9375bd8deadSopenharmony_ci self.gen.genType) 9385bd8deadSopenharmony_ci elif (ftype == 'command'): 9395bd8deadSopenharmony_ci for ptype in f.elem.findall('.//ptype'): 9405bd8deadSopenharmony_ci depname = ptype.text 9415bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Generating required parameter type', 9425bd8deadSopenharmony_ci depname) 9435bd8deadSopenharmony_ci self.generateFeature(depname, 'type', self.typedict, 9445bd8deadSopenharmony_ci self.gen.genType) 9455bd8deadSopenharmony_ci # 9465bd8deadSopenharmony_ci # Actually generate the type only if emitting declarations 9475bd8deadSopenharmony_ci if self.emitFeatures: 9485bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Emitting', ftype, 'decl for', fname) 9495bd8deadSopenharmony_ci genProc(f, fname) 9505bd8deadSopenharmony_ci else: 9515bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Skipping', ftype, fname, 9525bd8deadSopenharmony_ci '(not emitting this feature)') 9535bd8deadSopenharmony_ci # Always mark feature declared, as though actually emitted 9545bd8deadSopenharmony_ci f.declared = True 9555bd8deadSopenharmony_ci # 9565bd8deadSopenharmony_ci # generateRequiredInterface - generate all interfaces required 9575bd8deadSopenharmony_ci # by an API version or extension 9585bd8deadSopenharmony_ci # interface - Element for <version> or <extension> 9595bd8deadSopenharmony_ci def generateRequiredInterface(self, interface): 9605bd8deadSopenharmony_ci """Generate required C interface for specified API version/extension""" 9615bd8deadSopenharmony_ci # 9625bd8deadSopenharmony_ci # Loop over all features inside all <require> tags. 9635bd8deadSopenharmony_ci # <remove> tags are ignored (handled in pass 1). 9645bd8deadSopenharmony_ci for features in interface.findall('require'): 9655bd8deadSopenharmony_ci for t in features.findall('type'): 9665bd8deadSopenharmony_ci self.generateFeature(t.get('name'), 'type', self.typedict, 9675bd8deadSopenharmony_ci self.gen.genType) 9685bd8deadSopenharmony_ci for e in features.findall('enum'): 9695bd8deadSopenharmony_ci self.generateFeature(e.get('name'), 'enum', self.enumdict, 9705bd8deadSopenharmony_ci self.gen.genEnum) 9715bd8deadSopenharmony_ci for c in features.findall('command'): 9725bd8deadSopenharmony_ci self.generateFeature(c.get('name'), 'command', self.cmddict, 9735bd8deadSopenharmony_ci self.gen.genCmd) 9745bd8deadSopenharmony_ci # 9755bd8deadSopenharmony_ci # apiGen(genOpts) - generate interface for specified versions 9765bd8deadSopenharmony_ci # genOpts - GeneratorOptions object with parameters used 9775bd8deadSopenharmony_ci # by the Generator object. 9785bd8deadSopenharmony_ci def apiGen(self, genOpts): 9795bd8deadSopenharmony_ci """Generate interfaces for the specified API type and range of versions""" 9805bd8deadSopenharmony_ci # 9815bd8deadSopenharmony_ci self.gen.logMsg('diag', '*******************************************') 9825bd8deadSopenharmony_ci self.gen.logMsg('diag', ' Registry.apiGen file:', genOpts.filename, 9835bd8deadSopenharmony_ci 'api:', genOpts.apiname, 9845bd8deadSopenharmony_ci 'profile:', genOpts.profile) 9855bd8deadSopenharmony_ci self.gen.logMsg('diag', '*******************************************') 9865bd8deadSopenharmony_ci # 9875bd8deadSopenharmony_ci self.genOpts = genOpts 9885bd8deadSopenharmony_ci # Reset required/declared flags for all features 9895bd8deadSopenharmony_ci self.apiReset() 9905bd8deadSopenharmony_ci # 9915bd8deadSopenharmony_ci # Compile regexps used to select versions & extensions 9925bd8deadSopenharmony_ci regVersions = re.compile(self.genOpts.versions) 9935bd8deadSopenharmony_ci regEmitVersions = re.compile(self.genOpts.emitversions) 9945bd8deadSopenharmony_ci regAddExtensions = re.compile(self.genOpts.addExtensions) 9955bd8deadSopenharmony_ci regRemoveExtensions = re.compile(self.genOpts.removeExtensions) 9965bd8deadSopenharmony_ci # 9975bd8deadSopenharmony_ci # Get all matching API versions & add to list of FeatureInfo 9985bd8deadSopenharmony_ci features = [] 9995bd8deadSopenharmony_ci apiMatch = False 10005bd8deadSopenharmony_ci for key in self.apidict: 10015bd8deadSopenharmony_ci fi = self.apidict[key] 10025bd8deadSopenharmony_ci api = fi.elem.get('api') 10035bd8deadSopenharmony_ci if (api == self.genOpts.apiname): 10045bd8deadSopenharmony_ci apiMatch = True 10055bd8deadSopenharmony_ci if (regVersions.match(fi.number)): 10065bd8deadSopenharmony_ci # Matches API & version #s being generated. Mark for 10075bd8deadSopenharmony_ci # emission and add to the features[] list . 10085bd8deadSopenharmony_ci # @@ Could use 'declared' instead of 'emit'? 10095bd8deadSopenharmony_ci fi.emit = (regEmitVersions.match(fi.number) != None) 10105bd8deadSopenharmony_ci features.append(fi) 10115bd8deadSopenharmony_ci if (not fi.emit): 10125bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** NOT tagging feature api =', api, 10135bd8deadSopenharmony_ci 'name =', fi.name, 'number =', fi.number, 10145bd8deadSopenharmony_ci 'for emission (does not match emitversions pattern)') 10155bd8deadSopenharmony_ci else: 10165bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** NOT including feature api =', api, 10175bd8deadSopenharmony_ci 'name =', fi.name, 'number =', fi.number, 10185bd8deadSopenharmony_ci '(does not match requested versions)') 10195bd8deadSopenharmony_ci else: 10205bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** NOT including feature api =', api, 10215bd8deadSopenharmony_ci 'name =', fi.name, 10225bd8deadSopenharmony_ci '(does not match requested API)') 10235bd8deadSopenharmony_ci if (not apiMatch): 10245bd8deadSopenharmony_ci self.gen.logMsg('warn', '*** No matching API versions found!') 10255bd8deadSopenharmony_ci # 10265bd8deadSopenharmony_ci # Get all matching extensions & add to the list. 10275bd8deadSopenharmony_ci # Start with extensions tagged with 'api' pattern matching the API 10285bd8deadSopenharmony_ci # being generated. Add extensions matching the pattern specified in 10295bd8deadSopenharmony_ci # regExtensions, then remove extensions matching the pattern 10305bd8deadSopenharmony_ci # specified in regRemoveExtensions 10315bd8deadSopenharmony_ci for key in self.extdict: 10325bd8deadSopenharmony_ci ei = self.extdict[key] 10335bd8deadSopenharmony_ci extName = ei.name 10345bd8deadSopenharmony_ci include = False 10355bd8deadSopenharmony_ci # 10365bd8deadSopenharmony_ci # Include extension if defaultExtensions is not None and if the 10375bd8deadSopenharmony_ci # 'supported' attribute matches defaultExtensions. The regexp in 10385bd8deadSopenharmony_ci # 'supported' must exactly match defaultExtensions, so bracket 10395bd8deadSopenharmony_ci # it with ^(pat)$. 10405bd8deadSopenharmony_ci pat = '^(' + ei.elem.get('supported') + ')$' 10415bd8deadSopenharmony_ci if (self.genOpts.defaultExtensions and 10425bd8deadSopenharmony_ci re.match(pat, self.genOpts.defaultExtensions)): 10435bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Including extension', 10445bd8deadSopenharmony_ci extName, "(defaultExtensions matches the 'supported' attribute)") 10455bd8deadSopenharmony_ci include = True 10465bd8deadSopenharmony_ci # 10475bd8deadSopenharmony_ci # Include additional extensions if the extension name matches 10485bd8deadSopenharmony_ci # the regexp specified in the generator options. This allows 10495bd8deadSopenharmony_ci # forcing extensions into an interface even if they're not 10505bd8deadSopenharmony_ci # tagged appropriately in the registry. 10515bd8deadSopenharmony_ci if (regAddExtensions.match(extName) != None): 10525bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Including extension', 10535bd8deadSopenharmony_ci extName, '(matches explicitly requested extensions to add)') 10545bd8deadSopenharmony_ci include = True 10555bd8deadSopenharmony_ci # Remove extensions if the name matches the regexp specified 10565bd8deadSopenharmony_ci # in generator options. This allows forcing removal of 10575bd8deadSopenharmony_ci # extensions from an interface even if they're tagged that 10585bd8deadSopenharmony_ci # way in the registry. 10595bd8deadSopenharmony_ci if (regRemoveExtensions.match(extName) != None): 10605bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** Removing extension', 10615bd8deadSopenharmony_ci extName, '(matches explicitly requested extensions to remove)') 10625bd8deadSopenharmony_ci include = False 10635bd8deadSopenharmony_ci # 10645bd8deadSopenharmony_ci # If the extension is to be included, add it to the 10655bd8deadSopenharmony_ci # extension features list. 10665bd8deadSopenharmony_ci if (include): 10675bd8deadSopenharmony_ci ei.emit = True 10685bd8deadSopenharmony_ci features.append(ei) 10695bd8deadSopenharmony_ci else: 10705bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** NOT including extension', 10715bd8deadSopenharmony_ci extName, '(does not match api attribute or explicitly requested extensions)') 10725bd8deadSopenharmony_ci # 10735bd8deadSopenharmony_ci # Sort the extension features list, if a sort procedure is defined 10745bd8deadSopenharmony_ci if (self.genOpts.sortProcedure): 10755bd8deadSopenharmony_ci self.genOpts.sortProcedure(features) 10765bd8deadSopenharmony_ci # 10775bd8deadSopenharmony_ci # Pass 1: loop over requested API versions and extensions tagging 10785bd8deadSopenharmony_ci # types/commands/features as required (in an <require> block) or no 10795bd8deadSopenharmony_ci # longer required (in an <exclude> block). It is possible to remove 10805bd8deadSopenharmony_ci # a feature in one version and restore it later by requiring it in 10815bd8deadSopenharmony_ci # a later version. 10825bd8deadSopenharmony_ci # If a profile other than 'None' is being generated, it must 10835bd8deadSopenharmony_ci # match the profile attribute (if any) of the <require> and 10845bd8deadSopenharmony_ci # <remove> tags. 10855bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** PASS 1: TAG FEATURES ********************************************') 10865bd8deadSopenharmony_ci for f in features: 10875bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** PASS 1: Tagging required and removed features for', 10885bd8deadSopenharmony_ci f.name) 10895bd8deadSopenharmony_ci self.requireAndRemoveFeatures(f.elem, self.genOpts.apiname, self.genOpts.profile) 10905bd8deadSopenharmony_ci # 10915bd8deadSopenharmony_ci # Pass 2: loop over specified API versions and extensions printing 10925bd8deadSopenharmony_ci # declarations for required things which haven't already been 10935bd8deadSopenharmony_ci # generated. 10945bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** PASS 2: GENERATE INTERFACES FOR FEATURES ************************') 10955bd8deadSopenharmony_ci self.gen.beginFile(self.genOpts) 10965bd8deadSopenharmony_ci for f in features: 10975bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** PASS 2: Generating interface for', 10985bd8deadSopenharmony_ci f.name) 10995bd8deadSopenharmony_ci emit = self.emitFeatures = f.emit 11005bd8deadSopenharmony_ci if (not emit): 11015bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** PASS 2: NOT declaring feature', 11025bd8deadSopenharmony_ci f.elem.get('name'), 'because it is not tagged for emission') 11035bd8deadSopenharmony_ci # Generate the interface (or just tag its elements as having been 11045bd8deadSopenharmony_ci # emitted, if they haven't been). 11055bd8deadSopenharmony_ci self.gen.beginFeature(f.elem, emit) 11065bd8deadSopenharmony_ci self.generateRequiredInterface(f.elem) 11075bd8deadSopenharmony_ci self.gen.endFeature() 11085bd8deadSopenharmony_ci self.gen.endFile() 11095bd8deadSopenharmony_ci # 11105bd8deadSopenharmony_ci # apiReset - use between apiGen() calls to reset internal state 11115bd8deadSopenharmony_ci # 11125bd8deadSopenharmony_ci def apiReset(self): 11135bd8deadSopenharmony_ci """Reset type/enum/command dictionaries before generating another API""" 11145bd8deadSopenharmony_ci for type in self.typedict: 11155bd8deadSopenharmony_ci self.typedict[type].resetState() 11165bd8deadSopenharmony_ci for enum in self.enumdict: 11175bd8deadSopenharmony_ci self.enumdict[enum].resetState() 11185bd8deadSopenharmony_ci for cmd in self.cmddict: 11195bd8deadSopenharmony_ci self.cmddict[cmd].resetState() 11205bd8deadSopenharmony_ci for cmd in self.apidict: 11215bd8deadSopenharmony_ci self.apidict[cmd].resetState() 11225bd8deadSopenharmony_ci # 11235bd8deadSopenharmony_ci # validateGroups - check that group= attributes match actual groups 11245bd8deadSopenharmony_ci # 11255bd8deadSopenharmony_ci def validateGroups(self): 11265bd8deadSopenharmony_ci """Validate group= attributes on <param> and <proto> tags""" 11275bd8deadSopenharmony_ci # Keep track of group names not in <group> tags 11285bd8deadSopenharmony_ci badGroup = {} 11295bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** VALIDATING GROUP ATTRIBUTES ***') 11305bd8deadSopenharmony_ci for cmd in self.reg.findall('commands/command'): 11315bd8deadSopenharmony_ci proto = cmd.find('proto') 11325bd8deadSopenharmony_ci funcname = cmd.find('proto/name').text 11335bd8deadSopenharmony_ci if ('group' in proto.attrib.keys()): 11345bd8deadSopenharmony_ci group = proto.get('group') 11355bd8deadSopenharmony_ci # self.gen.logMsg('diag', '*** Command ', funcname, ' has return group ', group) 11365bd8deadSopenharmony_ci if (group not in self.groupdict.keys()): 11375bd8deadSopenharmony_ci # self.gen.logMsg('diag', '*** Command ', funcname, ' has UNKNOWN return group ', group) 11385bd8deadSopenharmony_ci if (group not in badGroup.keys()): 11395bd8deadSopenharmony_ci badGroup[group] = 1 11405bd8deadSopenharmony_ci else: 11415bd8deadSopenharmony_ci badGroup[group] = badGroup[group] + 1 11425bd8deadSopenharmony_ci for param in cmd.findall('param'): 11435bd8deadSopenharmony_ci pname = param.find('name') 11445bd8deadSopenharmony_ci if (pname != None): 11455bd8deadSopenharmony_ci pname = pname.text 11465bd8deadSopenharmony_ci else: 11475bd8deadSopenharmony_ci pname = type.get('name') 11485bd8deadSopenharmony_ci if ('group' in param.attrib.keys()): 11495bd8deadSopenharmony_ci group = param.get('group') 11505bd8deadSopenharmony_ci if (group not in self.groupdict.keys()): 11515bd8deadSopenharmony_ci # self.gen.logMsg('diag', '*** Command ', funcname, ' param ', pname, ' has UNKNOWN group ', group) 11525bd8deadSopenharmony_ci if (group not in badGroup.keys()): 11535bd8deadSopenharmony_ci badGroup[group] = 1 11545bd8deadSopenharmony_ci else: 11555bd8deadSopenharmony_ci badGroup[group] = badGroup[group] + 1 11565bd8deadSopenharmony_ci if (len(badGroup.keys()) > 0): 11575bd8deadSopenharmony_ci self.gen.logMsg('diag', '*** SUMMARY OF UNRECOGNIZED GROUPS ***') 11585bd8deadSopenharmony_ci for key in sorted(badGroup.keys()): 11595bd8deadSopenharmony_ci self.gen.logMsg('diag', ' ', key, ' occurred ', badGroup[key], ' times') 1160