1760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org#!/usr/bin/python 2760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# 3760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# Copyright (C) 2009 Chia-I Wu <olv@0xlab.org> 4760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# 5760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# Permission is hereby granted, free of charge, to any person obtaining a 6760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# copy of this software and associated documentation files (the "Software"), 7760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# to deal in the Software without restriction, including without limitation 8760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# on the rights to use, copy, modify, merge, publish, distribute, sub 9760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# license, and/or sell copies of the Software, and to permit persons to whom 10760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# the Software is furnished to do so, subject to the following conditions: 11760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# 12760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# The above copyright notice and this permission notice (including the next 13760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# paragraph) shall be included in all copies or substantial portions of the 14760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# Software. 15760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# 16760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org# IN THE SOFTWARE. 23760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org""" 24760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgA parser for APIspec. 25760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org""" 26760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 27760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass SpecError(Exception): 28760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Error in the spec file.""" 29760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 30760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 31760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass Spec(object): 32760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """A Spec is an abstraction of the API spec.""" 33760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 34760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __init__(self, doc): 35760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.doc = doc 36760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 37760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.spec_node = doc.getRootElement() 38760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.tmpl_nodes = {} 39760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.api_nodes = {} 40760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.impl_node = None 41760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 42760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # parse <apispec> 43760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = self.spec_node.children 44760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while node: 45760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.type == "element": 46760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.name == "template": 47760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.tmpl_nodes[node.prop("name")] = node 48760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif node.name == "api": 49760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.api_nodes[node.prop("name")] = node 50760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 51760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("unexpected node %s in apispec" % 52760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node.name) 53760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = node.next 54760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 55760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # find an implementation 56760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for name, node in self.api_nodes.iteritems(): 57760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.prop("implementation") == "true": 58760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.impl_node = node 59760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 60760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not self.impl_node: 61760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("unable to find an implementation") 62760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 63760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def get_impl(self): 64760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return the implementation.""" 65760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return API(self, self.impl_node) 66760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 67760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def get_api(self, name): 68760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return an API.""" 69760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return API(self, self.api_nodes[name]) 70760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 71760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 72760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass API(object): 73760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """An API consists of categories and functions.""" 74760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 75760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __init__(self, spec, api_node): 76760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.name = api_node.prop("name") 77760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.is_impl = (api_node.prop("implementation") == "true") 78760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 79760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.categories = [] 80760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.functions = [] 81760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 82760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # parse <api> 83760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org func_nodes = [] 84760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = api_node.children 85760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while node: 86760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.type == "element": 87760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.name == "category": 88760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org cat = node.prop("name") 89760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.categories.append(cat) 90760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif node.name == "function": 91760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org func_nodes.append(node) 92760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 93760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("unexpected node %s in api" % node.name) 94760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = node.next 95760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 96760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # realize functions 97760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for func_node in func_nodes: 98760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org tmpl_node = spec.tmpl_nodes[func_node.prop("template")] 99760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org try: 100760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org func = Function(tmpl_node, func_node, self.is_impl, 101760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.categories) 102760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org except SpecError, e: 103760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org func_name = func_node.prop("name") 104760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("failed to parse %s: %s" % (func_name, e)) 105760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.functions.append(func) 106760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 107760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def match(self, func, conversions={}): 108760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Find a matching function in the API.""" 109760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org match = None 110760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org need_conv = False 111760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for f in self.functions: 112760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org matched, conv = f.match(func, conversions) 113760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if matched: 114760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org match = f 115760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org need_conv = conv 116760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # exact match 117760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not need_conv: 118760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 119760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (match, need_conv) 120760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 121760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 122760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass Function(object): 123760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Parse and realize a <template> node.""" 124760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 125760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __init__(self, tmpl_node, func_node, force_skip_desc=False, categories=[]): 126760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.tmpl_name = tmpl_node.prop("name") 127760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.direction = tmpl_node.prop("direction") 128760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 129760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.name = func_node.prop("name") 130760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.prefix = func_node.prop("default_prefix") 131760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.is_external = (func_node.prop("external") == "true") 132760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 133760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if force_skip_desc: 134760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._skip_desc = True 135760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 136760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._skip_desc = (func_node.prop("skip_desc") == "true") 137760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 138760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._categories = categories 139760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 140760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # these attributes decide how the template is realized 141760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._gltype = func_node.prop("gltype") 142760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if func_node.hasProp("vector_size"): 143760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._vector_size = int(func_node.prop("vector_size")) 144760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 145760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._vector_size = 0 146760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._expand_vector = (func_node.prop("expand_vector") == "true") 147760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 148760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.return_type = "void" 149760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_nodes = [] 150760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 151760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # find <proto> 152760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org proto_node = tmpl_node.children 153760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while proto_node: 154760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if proto_node.type == "element" and proto_node.name == "proto": 155760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 156760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org proto_node = proto_node.next 157760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not proto_node: 158760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("no proto") 159760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # and parse it 160760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = proto_node.children 161760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while node: 162760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.type == "element": 163760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.name == "return": 164760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.return_type = node.prop("type") 165760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif node.name == "param" or node.name == "vector": 166760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if self.support_node(node): 167760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # make sure the node is not hidden 168760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not (self._expand_vector and 169760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org (node.prop("hide_if_expanded") == "true")): 170760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_nodes.append(node) 171760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 172760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("unexpected node %s in proto" % node.name) 173760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = node.next 174760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 175760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._init_params(param_nodes) 176760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._init_descs(tmpl_node, param_nodes) 177760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 178760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __str__(self): 179760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return "%s %s%s(%s)" % (self.return_type, self.prefix, self.name, 180760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.param_string(True)) 181760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 182760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def _init_params(self, param_nodes): 183760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Parse and initialize parameters.""" 184760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.params = [] 185760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 186760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for param_node in param_nodes: 187760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = self.param_node_size(param_node) 188760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # when no expansion, vector is just like param 189760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if param_node.name == "param" or not self._expand_vector: 190760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param = Parameter(param_node, self._gltype, size) 191760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.params.append(param) 192760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org continue 193760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 194760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not size or size > param_node.lsCountNode(): 195760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("could not expand %s with unknown or " 196760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org "mismatch sizes" % param.name) 197760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 198760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # expand the vector 199760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org expanded_params = [] 200760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org child = param_node.children 201760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while child: 202760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (child.type == "element" and child.name == "param" and 203760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.support_node(child)): 204760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org expanded_params.append(Parameter(child, self._gltype)) 205760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if len(expanded_params) == size: 206760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 207760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org child = child.next 208760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # just in case that lsCountNode counts unknown nodes 209760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if len(expanded_params) < size: 210760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("not enough named parameters") 211760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 212760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.params.extend(expanded_params) 213760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 214760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def _init_descs(self, tmpl_node, param_nodes): 215760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Parse and initialize parameter descriptions.""" 216760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.checker = Checker() 217760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if self._skip_desc: 218760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return 219760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 220760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = tmpl_node.children 221760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while node: 222760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.type == "element" and node.name == "desc": 223760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if self.support_node(node): 224760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # parse <desc> 225760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org desc = Description(node, self._categories) 226760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.checker.add_desc(desc) 227760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = node.next 228760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 229760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.checker.validate(self, param_nodes) 230760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 231760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def support_node(self, node): 232760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return true if a node is in the supported category.""" 233760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (not node.hasProp("category") or 234760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node.prop("category") in self._categories) 235760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 236760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def get_param(self, name): 237760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return the named parameter.""" 238760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for param in self.params: 239760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if param.name == name: 240760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return param 241760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return None 242760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 243760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def param_node_size(self, param): 244760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return the size of a vector.""" 245760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if param.name != "vector": 246760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return 0 247760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 248760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = param.prop("size") 249760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if size.isdigit(): 250760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = int(size) 251760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 252760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = 0 253760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not size: 254760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = self._vector_size 255760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not size and self._expand_vector: 256760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # return the number of named parameters 257760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = param.lsCountNode() 258760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return size 259760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 260760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def param_string(self, declaration): 261760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return the C code of the parameters.""" 262760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org args = [] 263760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if declaration: 264760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for param in self.params: 265760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org sep = "" if param.type.endswith("*") else " " 266760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org args.append("%s%s%s" % (param.type, sep, param.name)) 267760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not args: 268760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org args.append("void") 269760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 270760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for param in self.params: 271760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org args.append(param.name) 272760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return ", ".join(args) 273760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 274760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def match(self, other, conversions={}): 275760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return true if the functions match, probably with a conversion.""" 276760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (self.tmpl_name != other.tmpl_name or 277760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.return_type != other.return_type or 278760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org len(self.params) != len(other.params)): 279760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (False, False) 280760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 281760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org need_conv = False 282760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for i in xrange(len(self.params)): 283760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org src = other.params[i] 284760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org dst = self.params[i] 285760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (src.is_vector != dst.is_vector or src.size != dst.size): 286760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (False, False) 287760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if src.type != dst.type: 288760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if dst.base_type() in conversions.get(src.base_type(), []): 289760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org need_conv = True 290760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 291760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # unable to convert 292760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (False, False) 293760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 294760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (True, need_conv) 295760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 296760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 297760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass Parameter(object): 298760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """A parameter of a function.""" 299760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 300760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __init__(self, param_node, gltype=None, size=0): 301760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.is_vector = (param_node.name == "vector") 302760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 303760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.name = param_node.prop("name") 304760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.size = size 305760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 306760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org type = param_node.prop("type") 307760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if gltype: 308760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org type = type.replace("GLtype", gltype) 309760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif type.find("GLtype") != -1: 310760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("parameter %s has unresolved type" % self.name) 311760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 312760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.type = type 313760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 314760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def base_type(self): 315760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return the base GL type by stripping qualifiers.""" 316760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return [t for t in self.type.split(" ") if t.startswith("GL")][0] 317760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 318760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 319760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass Checker(object): 320760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """A checker is the collection of all descriptions on the same level. 321760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org Descriptions of the same parameter are concatenated. 322760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """ 323760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 324760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __init__(self): 325760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switches = {} 326760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switch_constants = {} 327760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 328760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def add_desc(self, desc): 329760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Add a description.""" 330760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # TODO allow index to vary 331760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org const_attrs = ["index", "error", "convert", "size_str"] 332760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if desc.name not in self.switches: 333760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switches[desc.name] = [] 334760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switch_constants[desc.name] = {} 335760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for attr in const_attrs: 336760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switch_constants[desc.name][attr] = None 337760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 338760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # some attributes, like error code, should be the same for all descs 339760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org consts = self.switch_constants[desc.name] 340760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for attr in const_attrs: 341760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if getattr(desc, attr) is not None: 342760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (consts[attr] is not None and 343760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org consts[attr] != getattr(desc, attr)): 344760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("mismatch %s for %s" % (attr, desc.name)) 345760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org consts[attr] = getattr(desc, attr) 346760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 347760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switches[desc.name].append(desc) 348760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 349760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def validate(self, func, param_nodes): 350760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Validate the checker against a function.""" 351760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org tmp = Checker() 352760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 353760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for switch in self.switches.itervalues(): 354760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org valid_descs = [] 355760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for desc in switch: 356760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if desc.validate(func, param_nodes): 357760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org valid_descs.append(desc) 358760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # no possible values 359760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not valid_descs: 360760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return False 361760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for desc in valid_descs: 362760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not desc._is_noop: 363760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org tmp.add_desc(desc) 364760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 365760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switches = tmp.switches 366760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.switch_constants = tmp.switch_constants 367760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return True 368760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 369760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def flatten(self, name=None): 370760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return a flat list of all descriptions of the named parameter.""" 371760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org flat_list = [] 372760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for switch in self.switches.itervalues(): 373760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for desc in switch: 374760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not name or desc.name == name: 375760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org flat_list.append(desc) 376760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org flat_list.extend(desc.checker.flatten(name)) 377760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return flat_list 378760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 379760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def always_check(self, name): 380760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Return true if the parameter is checked in all possible pathes.""" 381760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if name in self.switches: 382760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return True 383760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 384760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # a param is always checked if any of the switch always checks it 385760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for switch in self.switches.itervalues(): 386760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # a switch always checks it if all of the descs always check it 387760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org always = True 388760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for desc in switch: 389760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not desc.checker.always_check(name): 390760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org always = False 391760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 392760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if always: 393760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return True 394760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return False 395760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 396760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def _c_switch(self, name, indent="\t"): 397760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Output C switch-statement for the named parameter, for debug.""" 398760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org switch = self.switches.get(name, []) 399760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # make sure there are valid values 400760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org need_switch = False 401760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for desc in switch: 402760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if desc.values: 403760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org need_switch = True 404760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not need_switch: 405760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return [] 406760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 407760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts = [] 408760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org var = switch[0].name 409760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if switch[0].index >= 0: 410760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org var += "[%d]" % switch[0].index 411760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append("switch (%s) { /* assume GLenum */" % var) 412760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 413760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for desc in switch: 414760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if desc.values: 415760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for val in desc.values: 416760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append("case %s:" % val) 417760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for dep_name in desc.checker.switches.iterkeys(): 418760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org dep_stmts = [indent + s for s in desc.checker._c_switch(dep_name, indent)] 419760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.extend(dep_stmts) 420760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append(indent + "break;") 421760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 422760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append("default:") 423760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append(indent + "ON_ERROR(%s);" % switch[0].error); 424760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append(indent + "break;") 425760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts.append("}") 426760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 427760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return stmts 428760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 429760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def dump(self, indent="\t"): 430760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Dump the descriptions in C code.""" 431760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org stmts = [] 432760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for name in self.switches.iterkeys(): 433760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org c_switch = self._c_switch(name) 434760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org print "\n".join(c_switch) 435760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 436760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 437760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgclass Description(object): 438760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """A description desribes a parameter and its relationship with other 439760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org parameters. 440760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """ 441760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 442760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def __init__(self, desc_node, categories=[]): 443760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._categories = categories 444760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._is_noop = False 445760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 446760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.name = desc_node.prop("name") 447760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.index = -1 448760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 449760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.error = desc_node.prop("error") or "GL_INVALID_ENUM" 450760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # vector_size may be C code 451760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.size_str = desc_node.prop("vector_size") 452760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 453760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._has_enum = False 454760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.values = [] 455760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org dep_nodes = [] 456760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 457760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # parse <desc> 458760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org valid_names = ["value", "range", "desc"] 459760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = desc_node.children 460760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while node: 461760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.type == "element": 462760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.name in valid_names: 463760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # ignore nodes that require unsupported categories 464760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (node.prop("category") and 465760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node.prop("category") not in self._categories): 466760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = node.next 467760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org continue 468760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: 469760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("unexpected node %s in desc" % node.name) 470760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 471760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if node.name == "value": 472760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org val = node.prop("name") 473760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not self._has_enum and val.startswith("GL_"): 474760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._has_enum = True 475760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.values.append(val) 476760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif node.name == "range": 477760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org first = int(node.prop("from")) 478760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org last = int(node.prop("to")) 479760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org base = node.prop("base") or "" 480760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not self._has_enum and base.startswith("GL_"): 481760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._has_enum = True 482760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # expand range 483760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for i in xrange(first, last + 1): 484760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.values.append("%s%d" % (base, i)) 485760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org else: # dependent desc 486760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org dep_nodes.append(node) 487760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node = node.next 488760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 489760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # default to convert if there is no enum 490760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.convert = not self._has_enum 491760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if desc_node.hasProp("convert"): 492760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.convert = (desc_node.prop("convert") == "true") 493760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 494760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._init_deps(dep_nodes) 495760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 496760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def _init_deps(self, dep_nodes): 497760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Parse and initialize dependents.""" 498760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.checker = Checker() 499760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 500760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for dep_node in dep_nodes: 501760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # recursion! 502760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org dep = Description(dep_node, self._categories) 503760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.checker.add_desc(dep) 504760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 505760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def _search_param_node(self, param_nodes, name=None): 506760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Search the template parameters for the named node.""" 507760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_node = None 508760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_index = -1 509760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 510760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not name: 511760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org name = self.name 512760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for node in param_nodes: 513760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if name == node.prop("name"): 514760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_node = node 515760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif node.name == "vector": 516760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org child = node.children 517760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org idx = 0 518760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org while child: 519760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if child.type == "element" and child.name == "param": 520760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if name == child.prop("name"): 521760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_node = node 522760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_index = idx 523760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 524760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org idx += 1 525760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org child = child.next 526760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if param_node: 527760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org break 528760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (param_node, param_index) 529760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 530760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def _find_final(self, func, param_nodes): 531760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Find the final parameter.""" 532760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param = func.get_param(self.name) 533760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_index = -1 534760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 535760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # the described param is not in the final function 536760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not param: 537760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # search the template parameters 538760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org node, index = self._search_param_node(param_nodes) 539760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not node: 540760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("invalid desc %s in %s" % 541760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org (self.name, func.name)) 542760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 543760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # a named parameter of a vector 544760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if index >= 0: 545760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param = func.get_param(node.prop("name")) 546760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param_index = index 547760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif node.name == "vector": 548760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # must be an expanded vector, check its size 549760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if self.size_str and self.size_str.isdigit(): 550760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org size = int(self.size_str) 551760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org expanded_size = func.param_node_size(node) 552760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if size != expanded_size: 553760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (False, None, -1) 554760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # otherwise, it is a valid, but no-op, description 555760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 556760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return (True, param, param_index) 557760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 558760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org def validate(self, func, param_nodes): 559760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org """Validate a description against certain function.""" 560760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if self.checker.switches and not self.values: 561760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("no valid values for %s" % self.name) 562760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 563760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org valid, param, param_index = self._find_final(func, param_nodes) 564760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not valid: 565760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return False 566760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 567760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # the description is valid, but the param is gone 568760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # mark it no-op so that it will be skipped 569760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not param: 570760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self._is_noop = True 571760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return True 572760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 573760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if param.is_vector: 574760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # if param was known, this should have been done in __init__ 575760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if self._has_enum: 576760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.size_str = "1" 577760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # size mismatch 578760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if (param.size and self.size_str and self.size_str.isdigit() and 579760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org param.size != int(self.size_str)): 580760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return False 581760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org elif self.size_str: 582760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # only vector accepts vector_size 583760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org raise SpecError("vector_size is invalid for %s" % param.name) 584760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 585760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org if not self.checker.validate(func, param_nodes): 586760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return False 587760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 588760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org # update the description 589760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.name = param.name 590760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org self.index = param_index 591760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 592760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org return True 593760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 594760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 595760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgdef main(): 596760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org import libxml2 597760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 598760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org filename = "APIspec.xml" 599760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org apinames = ["GLES1.1", "GLES2.0"] 600760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 601760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org doc = libxml2.readFile(filename, None, 602760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org libxml2.XML_PARSE_DTDLOAD + 603760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org libxml2.XML_PARSE_DTDVALID + 604760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org libxml2.XML_PARSE_NOBLANKS) 605760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 606760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org spec = Spec(doc) 607760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org impl = spec.get_impl() 608760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org for apiname in apinames: 609760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org spec.get_api(apiname) 610760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 611760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org doc.freeDoc() 612760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 613760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org print "%s is successfully parsed" % filename 614760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 615760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org 616760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.orgif __name__ == "__main__": 617760fd893ba809a7a5daa25c2749ff502f7186e83kbr@chromium.org main() 618