1*3cc25752SFrank Piva# Copyright (c) 2021 The Khronos Group Inc. 2*3cc25752SFrank Piva# 3*3cc25752SFrank Piva# Licensed under the Apache License, Version 2.0 (the "License"); 4*3cc25752SFrank Piva# you may not use this file except in compliance with the License. 5*3cc25752SFrank Piva# You may obtain a copy of the License at 6*3cc25752SFrank Piva# 7*3cc25752SFrank Piva# http://www.apache.org/licenses/LICENSE-2.0 8*3cc25752SFrank Piva# 9*3cc25752SFrank Piva# Unless required by applicable law or agreed to in writing, software 10*3cc25752SFrank Piva# distributed under the License is distributed on an "AS IS" BASIS, 11*3cc25752SFrank Piva# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*3cc25752SFrank Piva# See the License for the specific language governing permissions and 13*3cc25752SFrank Piva# limitations under the License. 14*3cc25752SFrank Piva 15*3cc25752SFrank Pivafrom collections import OrderedDict 16*3cc25752SFrank Pivafrom collections import namedtuple 17*3cc25752SFrank Piva 18*3cc25752SFrank Pivaimport argparse 19*3cc25752SFrank Pivaimport sys 20*3cc25752SFrank Pivaimport urllib 21*3cc25752SFrank Pivaimport xml.etree.ElementTree as etree 22*3cc25752SFrank Pivaimport urllib.request 23*3cc25752SFrank Piva 24*3cc25752SFrank Piva# parse_xml - Helper function to parse the XML file from a URL or local file. 25*3cc25752SFrank Pivadef parse_xml(path): 26*3cc25752SFrank Piva file = urllib.request.urlopen(path) if path.startswith("http") else open(path, 'r') 27*3cc25752SFrank Piva with file: 28*3cc25752SFrank Piva tree = etree.parse(file) 29*3cc25752SFrank Piva return tree 30*3cc25752SFrank Piva 31*3cc25752SFrank Piva# noneStr - returns string argument, or "" if argument is None. 32*3cc25752SFrank Pivadef noneStr(s): 33*3cc25752SFrank Piva if s: 34*3cc25752SFrank Piva return s 35*3cc25752SFrank Piva return "" 36*3cc25752SFrank Piva 37*3cc25752SFrank Pivadef parse_args(): 38*3cc25752SFrank Piva parser = argparse.ArgumentParser() 39*3cc25752SFrank Piva 40*3cc25752SFrank Piva # To pull the latest registry file from GitHub, pass: 41*3cc25752SFrank Piva # -registry "https://raw.githubusercontent.com/KhronosGroup/OpenCL-Registry/master/xml/cl.xml" 42*3cc25752SFrank Piva 43*3cc25752SFrank Piva parser.add_argument('-registry', action='store', 44*3cc25752SFrank Piva default='cl.xml', 45*3cc25752SFrank Piva help='Use specified registry file instead of cl.xml') 46*3cc25752SFrank Piva parser.add_argument('-o', action='store', dest='directory', 47*3cc25752SFrank Piva default='.', 48*3cc25752SFrank Piva help='Create target and related files in specified directory') 49*3cc25752SFrank Piva 50*3cc25752SFrank Piva args = parser.parse_args() 51*3cc25752SFrank Piva return args 52*3cc25752SFrank Piva 53*3cc25752SFrank Pivadef load_spec(args): 54*3cc25752SFrank Piva specpath = args.registry 55*3cc25752SFrank Piva 56*3cc25752SFrank Piva print('Parsing XML file from: ' + specpath) 57*3cc25752SFrank Piva spec = parse_xml(specpath) 58*3cc25752SFrank Piva return spec 59*3cc25752SFrank Piva 60*3cc25752SFrank Pivadef get_apitypedefs(spec): 61*3cc25752SFrank Piva typedefs = OrderedDict() 62*3cc25752SFrank Piva Typedef = namedtuple('Typedef', 'Typedef Name') 63*3cc25752SFrank Piva print('Generating API typedef dictionary...') 64*3cc25752SFrank Piva for type in spec.findall('types/type'): 65*3cc25752SFrank Piva if type.get('category') == 'define': 66*3cc25752SFrank Piva if noneStr(type.text).startswith("typedef"): 67*3cc25752SFrank Piva typedef = noneStr(type.text) 68*3cc25752SFrank Piva name = "" 69*3cc25752SFrank Piva for elem in type: 70*3cc25752SFrank Piva if elem.tag == 'name': 71*3cc25752SFrank Piva name = noneStr(elem.text) 72*3cc25752SFrank Piva else: 73*3cc25752SFrank Piva typedef = typedef + noneStr(elem.text) + noneStr(elem.tail) 74*3cc25752SFrank Piva typedef = typedef.strip() 75*3cc25752SFrank Piva name = name.strip() 76*3cc25752SFrank Piva typedefs[name] = Typedef(typedef, name) 77*3cc25752SFrank Piva return typedefs 78*3cc25752SFrank Piva 79*3cc25752SFrank Pivadef get_apimacros(spec): 80*3cc25752SFrank Piva macros = OrderedDict() 81*3cc25752SFrank Piva Macro = namedtuple('Macro', 'Define Name Macro') 82*3cc25752SFrank Piva print('Generating API macro dictionary...') 83*3cc25752SFrank Piva for type in spec.findall('types/type'): 84*3cc25752SFrank Piva if type.get('category') == 'define': 85*3cc25752SFrank Piva if noneStr(type.text).startswith("#define"): 86*3cc25752SFrank Piva define = noneStr(type.text) 87*3cc25752SFrank Piva name = "" 88*3cc25752SFrank Piva macro = "" 89*3cc25752SFrank Piva for elem in type: 90*3cc25752SFrank Piva if elem.tag == 'name': 91*3cc25752SFrank Piva name = noneStr(elem.text) 92*3cc25752SFrank Piva macro = macro + noneStr(elem.tail) 93*3cc25752SFrank Piva define = define.strip() 94*3cc25752SFrank Piva name = name.strip() 95*3cc25752SFrank Piva macro = macro.rstrip() # keep spaces on the left! 96*3cc25752SFrank Piva macros[name] = Macro(define, name, macro) 97*3cc25752SFrank Piva return macros 98*3cc25752SFrank Piva 99*3cc25752SFrank Pivadef get_apistructs(spec): 100*3cc25752SFrank Piva structs = OrderedDict() 101*3cc25752SFrank Piva Struct = namedtuple('Struct', 'Name Members') 102*3cc25752SFrank Piva StructMember = namedtuple('StructMember', 'Type TypeEnd Name') 103*3cc25752SFrank Piva print('Generating API struct dictionary...') 104*3cc25752SFrank Piva for type in spec.findall('types/type'): 105*3cc25752SFrank Piva if type.get('category') == 'struct': 106*3cc25752SFrank Piva name = type.get('name') 107*3cc25752SFrank Piva mlist = [] 108*3cc25752SFrank Piva for member in type.findall('member'): 109*3cc25752SFrank Piva mtype = noneStr(member.text) 110*3cc25752SFrank Piva mtypeend = "" 111*3cc25752SFrank Piva mname = "" 112*3cc25752SFrank Piva for elem in member: 113*3cc25752SFrank Piva if elem.tag == 'name': 114*3cc25752SFrank Piva mname = noneStr(elem.text) 115*3cc25752SFrank Piva mtypeend = noneStr(elem.tail) 116*3cc25752SFrank Piva elif elem.tag == 'enum': 117*3cc25752SFrank Piva # Assumes any additional enums are for array limits, e.g.: 118*3cc25752SFrank Piva # <member><type>char</type><name>name</name>[<enum>CL_NAME_VERSION_MAX_NAME_SIZE</enum>]</member> 119*3cc25752SFrank Piva mtypeend = mtypeend + noneStr(elem.text) + noneStr(elem.tail) 120*3cc25752SFrank Piva else: 121*3cc25752SFrank Piva mtype = mtype + noneStr(elem.text) + noneStr(elem.tail) 122*3cc25752SFrank Piva mtype = mtype.strip() 123*3cc25752SFrank Piva mtypeend = mtypeend.strip() 124*3cc25752SFrank Piva mname = mname.strip() 125*3cc25752SFrank Piva mlist.append(StructMember(mtype, mtypeend, mname)) 126*3cc25752SFrank Piva structs[name] = Struct(name, mlist) 127*3cc25752SFrank Piva return structs 128*3cc25752SFrank Piva 129*3cc25752SFrank Pivadef get_apienums(spec): 130*3cc25752SFrank Piva enums = OrderedDict() 131*3cc25752SFrank Piva Enum = namedtuple('Enum', 'Value Bitpos Name') 132*3cc25752SFrank Piva print('Generating API enum dictionary...') 133*3cc25752SFrank Piva for enum in spec.findall('enums/enum'): 134*3cc25752SFrank Piva value = enum.get('value') 135*3cc25752SFrank Piva bitpos = enum.get('bitpos') 136*3cc25752SFrank Piva name = enum.get('name') 137*3cc25752SFrank Piva enums[name] = Enum(value, bitpos, name) 138*3cc25752SFrank Piva return enums 139*3cc25752SFrank Piva 140*3cc25752SFrank Pivadef get_apisigs(spec): 141*3cc25752SFrank Piva apisigs = OrderedDict() 142*3cc25752SFrank Piva ApiSignature = namedtuple('ApiSignature', 'Name RetType Params Suffix') 143*3cc25752SFrank Piva ApiParam = namedtuple('ApiParam', 'Type TypeEnd Name') 144*3cc25752SFrank Piva print('Generating API signatures dictionary...') 145*3cc25752SFrank Piva for command in spec.findall('commands/command'): 146*3cc25752SFrank Piva suffix = noneStr(command.get('suffix')) 147*3cc25752SFrank Piva proto = command.find('proto') 148*3cc25752SFrank Piva ret = noneStr(proto.text) 149*3cc25752SFrank Piva name = "" 150*3cc25752SFrank Piva params = "" 151*3cc25752SFrank Piva for elem in proto: 152*3cc25752SFrank Piva if elem.tag == 'name': 153*3cc25752SFrank Piva name = noneStr(elem.text) + noneStr(elem.tail) 154*3cc25752SFrank Piva else: 155*3cc25752SFrank Piva ret = ret + noneStr(elem.text) + noneStr(elem.tail) 156*3cc25752SFrank Piva ret = ret.strip() 157*3cc25752SFrank Piva name = name.strip() 158*3cc25752SFrank Piva 159*3cc25752SFrank Piva plist = [] 160*3cc25752SFrank Piva for param in command.findall('param'): 161*3cc25752SFrank Piva ptype = noneStr(param.text) 162*3cc25752SFrank Piva ptypeend = "" 163*3cc25752SFrank Piva pname = "" 164*3cc25752SFrank Piva for elem in param: 165*3cc25752SFrank Piva if elem.tag == 'name': 166*3cc25752SFrank Piva pname = noneStr(elem.text) 167*3cc25752SFrank Piva ptypeend = noneStr(elem.tail) 168*3cc25752SFrank Piva else: 169*3cc25752SFrank Piva ptype = ptype + noneStr(elem.text) + noneStr(elem.tail) 170*3cc25752SFrank Piva ptype = ptype.strip() 171*3cc25752SFrank Piva ptypeend = ptypeend.strip() 172*3cc25752SFrank Piva pname = pname.strip() 173*3cc25752SFrank Piva plist.append(ApiParam(ptype, ptypeend, pname)) 174*3cc25752SFrank Piva 175*3cc25752SFrank Piva # For an empty parameter list (for e.g. clUnloadCompiler), add a single 176*3cc25752SFrank Piva # unnamed void parameter to make generation easier. 177*3cc25752SFrank Piva if len(plist) == 0: 178*3cc25752SFrank Piva plist.append(ApiParam("void", "", "")) 179*3cc25752SFrank Piva 180*3cc25752SFrank Piva apisigs[name] = ApiSignature(name, ret, plist, suffix) 181*3cc25752SFrank Piva return apisigs 182*3cc25752SFrank Piva 183*3cc25752SFrank Pivadef get_coreapis(spec, apisigs): 184*3cc25752SFrank Piva coreapis = OrderedDict() 185*3cc25752SFrank Piva print('Generating core API dictionary...') 186*3cc25752SFrank Piva for feature in spec.findall('feature'): 187*3cc25752SFrank Piva version = noneStr(feature.get('name')) 188*3cc25752SFrank Piva 189*3cc25752SFrank Piva alist = [] 190*3cc25752SFrank Piva for function in feature.findall('require/command'): 191*3cc25752SFrank Piva name = function.get('name') 192*3cc25752SFrank Piva alist.append(apisigs[name]) 193*3cc25752SFrank Piva coreapis[version] = alist 194*3cc25752SFrank Piva return coreapis 195*3cc25752SFrank Piva 196*3cc25752SFrank Pivadef get_extapis(spec, apisigs): 197*3cc25752SFrank Piva extapis = OrderedDict() 198*3cc25752SFrank Piva print('Generating API extensions dictionary...') 199*3cc25752SFrank Piva for feature in spec.findall('extensions/extension'): 200*3cc25752SFrank Piva extension = noneStr(feature.get('name')) 201*3cc25752SFrank Piva 202*3cc25752SFrank Piva alist = [] 203*3cc25752SFrank Piva for function in feature.findall('require/command'): 204*3cc25752SFrank Piva name = function.get('name') 205*3cc25752SFrank Piva alist.append(apisigs[name]) 206*3cc25752SFrank Piva extapis[extension] = alist 207*3cc25752SFrank Piva return extapis 208*3cc25752SFrank Piva 209*3cc25752SFrank Pivadef get_apis(spec, apisigs): 210*3cc25752SFrank Piva return (get_coreapis(spec, apisigs), get_extapis(spec, apisigs)) 211