10c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu#!/usr/bin/python 20c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# 30c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# Copyright (C) 2009 Chia-I Wu <olv@0xlab.org> 40c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# 50c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# Permission is hereby granted, free of charge, to any person obtaining a 60c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# copy of this software and associated documentation files (the "Software"), 70c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# to deal in the Software without restriction, including without limitation 80c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# on the rights to use, copy, modify, merge, publish, distribute, sub 90c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# license, and/or sell copies of the Software, and to permit persons to whom 100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# the Software is furnished to do so, subject to the following conditions: 110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# 120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# The above copyright notice and this permission notice (including the next 130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# paragraph) shall be included in all copies or substantial portions of the 140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# Software. 150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# 160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 180c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 190c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 200c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 210c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 220c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu# IN THE SOFTWARE. 230c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu""" 240c1a7bbe0d0c6727a432890164032188787e7e26Chia-I WuA parser for APIspec. 250c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu""" 260c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 270c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass SpecError(Exception): 280c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Error in the spec file.""" 290c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 300c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 310c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass Spec(object): 320c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """A Spec is an abstraction of the API spec.""" 330c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 340c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __init__(self, doc): 350c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.doc = doc 360c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 370c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.spec_node = doc.getRootElement() 380c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.tmpl_nodes = {} 390c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.api_nodes = {} 400c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.impl_node = None 410c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 420c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # parse <apispec> 430c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = self.spec_node.children 440c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while node: 450c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.type == "element": 460c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.name == "template": 470c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.tmpl_nodes[node.prop("name")] = node 480c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif node.name == "api": 490c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.api_nodes[node.prop("name")] = node 500c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 510c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("unexpected node %s in apispec" % 520c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node.name) 530c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = node.next 540c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 550c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # find an implementation 560c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for name, node in self.api_nodes.iteritems(): 570c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.prop("implementation") == "true": 580c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.impl_node = node 590c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 600c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not self.impl_node: 610c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("unable to find an implementation") 620c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 630c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def get_impl(self): 640c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return the implementation.""" 650c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return API(self, self.impl_node) 660c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 670c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def get_api(self, name): 680c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return an API.""" 690c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return API(self, self.api_nodes[name]) 700c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 710c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 720c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass API(object): 730c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """An API consists of categories and functions.""" 740c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 750c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __init__(self, spec, api_node): 760c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.name = api_node.prop("name") 770c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.is_impl = (api_node.prop("implementation") == "true") 780c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 790c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.categories = [] 800c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.functions = [] 810c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 820c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # parse <api> 830c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu func_nodes = [] 840c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = api_node.children 850c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while node: 860c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.type == "element": 870c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.name == "category": 880c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu cat = node.prop("name") 890c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.categories.append(cat) 900c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif node.name == "function": 910c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu func_nodes.append(node) 920c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 930c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("unexpected node %s in api" % node.name) 940c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = node.next 950c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 960c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # realize functions 970c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for func_node in func_nodes: 980c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu tmpl_node = spec.tmpl_nodes[func_node.prop("template")] 990c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu try: 1000c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu func = Function(tmpl_node, func_node, self.is_impl, 1010c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.categories) 1020c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu except SpecError, e: 1030c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu func_name = func_node.prop("name") 1040c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("failed to parse %s: %s" % (func_name, e)) 1050c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.functions.append(func) 1060c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1070c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def match(self, func, conversions={}): 1080c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Find a matching function in the API.""" 1090c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu match = None 1100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu need_conv = False 1110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for f in self.functions: 1120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu matched, conv = f.match(func, conversions) 1130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if matched: 1140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu match = f 1150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu need_conv = conv 1160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # exact match 1170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not need_conv: 1180c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 1190c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (match, need_conv) 1200c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1210c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1220c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass Function(object): 1230c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Parse and realize a <template> node.""" 1240c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1250c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __init__(self, tmpl_node, func_node, force_skip_desc=False, categories=[]): 1260c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.tmpl_name = tmpl_node.prop("name") 1270c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.direction = tmpl_node.prop("direction") 1280c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1290c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.name = func_node.prop("name") 1300c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.prefix = func_node.prop("default_prefix") 1310c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.is_external = (func_node.prop("external") == "true") 1320c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1330c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if force_skip_desc: 1340c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._skip_desc = True 1350c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 136a2d21f67f901ec34799819ba47b9579ac78bf112Chia-I Wu self._skip_desc = (func_node.prop("skip_desc") == "true") 1370c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1380c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._categories = categories 1390c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1400c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # these attributes decide how the template is realized 1410c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._gltype = func_node.prop("gltype") 1420c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if func_node.hasProp("vector_size"): 1430c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._vector_size = int(func_node.prop("vector_size")) 1440c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 1450c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._vector_size = 0 1460c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._expand_vector = (func_node.prop("expand_vector") == "true") 1470c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1480c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.return_type = "void" 1490c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_nodes = [] 1500c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1510c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # find <proto> 1520c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu proto_node = tmpl_node.children 1530c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while proto_node: 1540c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if proto_node.type == "element" and proto_node.name == "proto": 1550c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 1560c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu proto_node = proto_node.next 1570c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not proto_node: 1580c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("no proto") 1590c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # and parse it 1600c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = proto_node.children 1610c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while node: 1620c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.type == "element": 1630c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.name == "return": 1640c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.return_type = node.prop("type") 1650c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif node.name == "param" or node.name == "vector": 1660c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if self.support_node(node): 1670c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # make sure the node is not hidden 1680c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not (self._expand_vector and 1690c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu (node.prop("hide_if_expanded") == "true")): 1700c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_nodes.append(node) 1710c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 1720c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("unexpected node %s in proto" % node.name) 1730c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = node.next 1740c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1750c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._init_params(param_nodes) 1760c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._init_descs(tmpl_node, param_nodes) 1770c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1780c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __str__(self): 1790c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return "%s %s%s(%s)" % (self.return_type, self.prefix, self.name, 1800c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.param_string(True)) 1810c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1820c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def _init_params(self, param_nodes): 1830c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Parse and initialize parameters.""" 1840c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.params = [] 1850c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1860c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for param_node in param_nodes: 1870c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = self.param_node_size(param_node) 1880c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # when no expansion, vector is just like param 1890c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if param_node.name == "param" or not self._expand_vector: 1900c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param = Parameter(param_node, self._gltype, size) 1910c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.params.append(param) 1920c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu continue 1930c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1940c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not size or size > param_node.lsCountNode(): 1950c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("could not expand %s with unknown or " 1960c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu "mismatch sizes" % param.name) 1970c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 1980c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # expand the vector 1990c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu expanded_params = [] 2000c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu child = param_node.children 2010c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while child: 2020c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if (child.type == "element" and child.name == "param" and 2030c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.support_node(child)): 2040c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu expanded_params.append(Parameter(child, self._gltype)) 2050c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if len(expanded_params) == size: 2060c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 2070c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu child = child.next 2080c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # just in case that lsCountNode counts unknown nodes 2090c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if len(expanded_params) < size: 2100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("not enough named parameters") 2110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.params.extend(expanded_params) 2130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def _init_descs(self, tmpl_node, param_nodes): 2150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Parse and initialize parameter descriptions.""" 2160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.checker = Checker() 2170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if self._skip_desc: 2180c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return 2190c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2200c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = tmpl_node.children 2210c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while node: 2220c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.type == "element" and node.name == "desc": 2230c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if self.support_node(node): 2240c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # parse <desc> 2250c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu desc = Description(node, self._categories) 2260c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.checker.add_desc(desc) 2270c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = node.next 2280c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2290c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.checker.validate(self, param_nodes) 2300c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2310c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def support_node(self, node): 2320c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return true if a node is in the supported category.""" 2330c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (not node.hasProp("category") or 2340c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node.prop("category") in self._categories) 2350c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2360c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def get_param(self, name): 2370c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return the named parameter.""" 2380c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for param in self.params: 2390c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if param.name == name: 2400c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return param 2410c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return None 2420c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2430c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def param_node_size(self, param): 2440c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return the size of a vector.""" 2450c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if param.name != "vector": 2460c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return 0 2470c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2480c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = param.prop("size") 2490c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if size.isdigit(): 2500c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = int(size) 2510c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 2520c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = 0 2530c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not size: 2540c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = self._vector_size 2550c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not size and self._expand_vector: 2560c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # return the number of named parameters 2570c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = param.lsCountNode() 2580c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return size 2590c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2600c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def param_string(self, declaration): 2610c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return the C code of the parameters.""" 2620c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu args = [] 2630c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if declaration: 2640c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for param in self.params: 2650c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu sep = "" if param.type.endswith("*") else " " 2660c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu args.append("%s%s%s" % (param.type, sep, param.name)) 2670c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not args: 2680c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu args.append("void") 2690c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 2700c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for param in self.params: 2710c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu args.append(param.name) 2720c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return ", ".join(args) 2730c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2740c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def match(self, other, conversions={}): 2750c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return true if the functions match, probably with a conversion.""" 2760c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if (self.tmpl_name != other.tmpl_name or 2770c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.return_type != other.return_type or 2780c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu len(self.params) != len(other.params)): 2790c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (False, False) 2800c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2810c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu need_conv = False 2820c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for i in xrange(len(self.params)): 2830c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu src = other.params[i] 2840c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu dst = self.params[i] 2850c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if (src.is_vector != dst.is_vector or src.size != dst.size): 2860c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (False, False) 2870c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if src.type != dst.type: 2880c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if dst.base_type() in conversions.get(src.base_type(), []): 2890c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu need_conv = True 2900c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 2910c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # unable to convert 2920c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (False, False) 2930c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2940c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (True, need_conv) 2950c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2960c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 2970c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass Parameter(object): 2980c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """A parameter of a function.""" 2990c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3000c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __init__(self, param_node, gltype=None, size=0): 3010c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.is_vector = (param_node.name == "vector") 3020c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3030c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.name = param_node.prop("name") 3040c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.size = size 3050c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3060c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu type = param_node.prop("type") 3070c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if gltype: 3080c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu type = type.replace("GLtype", gltype) 3090c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif type.find("GLtype") != -1: 3100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("parameter %s has unresolved type" % self.name) 3110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.type = type 3130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def base_type(self): 3150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return the base GL type by stripping qualifiers.""" 3160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return [t for t in self.type.split(" ") if t.startswith("GL")][0] 3170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3180c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3190c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass Checker(object): 3200c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """A checker is the collection of all descriptions on the same level. 3210c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu Descriptions of the same parameter are concatenated. 3220c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """ 3230c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3240c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __init__(self): 3250c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.switches = {} 326c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu self.switch_constants = {} 3270c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3280c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def add_desc(self, desc): 3290c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Add a description.""" 330c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu # TODO allow index to vary 331c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu const_attrs = ["index", "error", "convert", "size_str"] 3320c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if desc.name not in self.switches: 3330c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.switches[desc.name] = [] 334c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu self.switch_constants[desc.name] = {} 335c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu for attr in const_attrs: 336c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu self.switch_constants[desc.name][attr] = None 337c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu 338c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu # some attributes, like error code, should be the same for all descs 339c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu consts = self.switch_constants[desc.name] 340c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu for attr in const_attrs: 341c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu if getattr(desc, attr) is not None: 342c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu if (consts[attr] is not None and 343c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu consts[attr] != getattr(desc, attr)): 344c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu raise SpecError("mismatch %s for %s" % (attr, desc.name)) 345c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu consts[attr] = getattr(desc, attr) 346c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu 3470c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.switches[desc.name].append(desc) 3480c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3490c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def validate(self, func, param_nodes): 3500c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Validate the checker against a function.""" 3510c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu tmp = Checker() 3520c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3530c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for switch in self.switches.itervalues(): 3540c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu valid_descs = [] 3550c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for desc in switch: 3560c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if desc.validate(func, param_nodes): 3570c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu valid_descs.append(desc) 3580c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # no possible values 3590c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not valid_descs: 3600c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return False 3610c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for desc in valid_descs: 3620c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not desc._is_noop: 3630c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu tmp.add_desc(desc) 3640c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3650c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.switches = tmp.switches 366c3bd85791766e4a6f3896ea724e18640e56c6808Chia-I Wu self.switch_constants = tmp.switch_constants 3670c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return True 3680c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3690c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def flatten(self, name=None): 3700c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return a flat list of all descriptions of the named parameter.""" 3710c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu flat_list = [] 3720c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for switch in self.switches.itervalues(): 3730c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for desc in switch: 3740c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not name or desc.name == name: 3750c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu flat_list.append(desc) 3760c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu flat_list.extend(desc.checker.flatten(name)) 3770c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return flat_list 3780c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3790c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def always_check(self, name): 3800c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Return true if the parameter is checked in all possible pathes.""" 3810c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if name in self.switches: 3820c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return True 3830c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3840c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # a param is always checked if any of the switch always checks it 3850c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for switch in self.switches.itervalues(): 3860c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # a switch always checks it if all of the descs always check it 3870c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu always = True 3880c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for desc in switch: 3890c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not desc.checker.always_check(name): 3900c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu always = False 3910c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 3920c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if always: 3930c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return True 3940c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return False 3950c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 3960c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def _c_switch(self, name, indent="\t"): 3970c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Output C switch-statement for the named parameter, for debug.""" 3980c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu switch = self.switches.get(name, []) 3990c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # make sure there are valid values 4000c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu need_switch = False 4010c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for desc in switch: 4020c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if desc.values: 4030c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu need_switch = True 4040c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not need_switch: 4050c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return [] 4060c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4070c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts = [] 4080c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu var = switch[0].name 4090c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if switch[0].index >= 0: 4100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu var += "[%d]" % switch[0].index 4110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append("switch (%s) { /* assume GLenum */" % var) 4120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for desc in switch: 4140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if desc.values: 4150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for val in desc.values: 4160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append("case %s:" % val) 4170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for dep_name in desc.checker.switches.iterkeys(): 4180c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu dep_stmts = [indent + s for s in desc.checker._c_switch(dep_name, indent)] 4190c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.extend(dep_stmts) 4200c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append(indent + "break;") 4210c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4220c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append("default:") 4230c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append(indent + "ON_ERROR(%s);" % switch[0].error); 4240c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append(indent + "break;") 4250c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts.append("}") 4260c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4270c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return stmts 4280c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4290c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def dump(self, indent="\t"): 4300c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Dump the descriptions in C code.""" 4310c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu stmts = [] 4320c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for name in self.switches.iterkeys(): 4330c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu c_switch = self._c_switch(name) 4340c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu print "\n".join(c_switch) 4350c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4360c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4370c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuclass Description(object): 4380c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """A description desribes a parameter and its relationship with other 4390c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu parameters. 4400c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """ 4410c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4420c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def __init__(self, desc_node, categories=[]): 4430c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._categories = categories 4440c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._is_noop = False 4450c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4460c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.name = desc_node.prop("name") 4470c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.index = -1 4480c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4490c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.error = desc_node.prop("error") or "GL_INVALID_ENUM" 4500c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # vector_size may be C code 4510c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.size_str = desc_node.prop("vector_size") 4520c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4530c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._has_enum = False 4540c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.values = [] 4550c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu dep_nodes = [] 4560c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4570c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # parse <desc> 4580c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu valid_names = ["value", "range", "desc"] 4590c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = desc_node.children 4600c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while node: 4610c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.type == "element": 4620c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.name in valid_names: 4630c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # ignore nodes that require unsupported categories 4640c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if (node.prop("category") and 4650c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node.prop("category") not in self._categories): 4660c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = node.next 4670c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu continue 4680c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: 4690c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("unexpected node %s in desc" % node.name) 4700c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4710c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if node.name == "value": 4720c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu val = node.prop("name") 4730c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not self._has_enum and val.startswith("GL_"): 4740c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._has_enum = True 4750c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.values.append(val) 4760c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif node.name == "range": 4770c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu first = int(node.prop("from")) 4780c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu last = int(node.prop("to")) 4790c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu base = node.prop("base") or "" 4800c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not self._has_enum and base.startswith("GL_"): 4810c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._has_enum = True 4820c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # expand range 4830c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for i in xrange(first, last + 1): 4840c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.values.append("%s%d" % (base, i)) 4850c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu else: # dependent desc 4860c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu dep_nodes.append(node) 4870c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node = node.next 4880c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4890c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # default to convert if there is no enum 4900c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.convert = not self._has_enum 4910c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if desc_node.hasProp("convert"): 4920c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.convert = (desc_node.prop("convert") == "true") 4930c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4940c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._init_deps(dep_nodes) 4950c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 4960c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def _init_deps(self, dep_nodes): 4970c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Parse and initialize dependents.""" 4980c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.checker = Checker() 4990c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5000c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for dep_node in dep_nodes: 5010c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # recursion! 5020c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu dep = Description(dep_node, self._categories) 5030c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.checker.add_desc(dep) 5040c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5050c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def _search_param_node(self, param_nodes, name=None): 5060c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Search the template parameters for the named node.""" 5070c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_node = None 5080c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_index = -1 5090c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not name: 5110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu name = self.name 5120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for node in param_nodes: 5130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if name == node.prop("name"): 5140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_node = node 5150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif node.name == "vector": 5160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu child = node.children 5170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu idx = 0 5180c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu while child: 5190c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if child.type == "element" and child.name == "param": 5200c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if name == child.prop("name"): 5210c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_node = node 5220c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_index = idx 5230c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 5240c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu idx += 1 5250c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu child = child.next 5260c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if param_node: 5270c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu break 5280c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (param_node, param_index) 5290c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5300c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def _find_final(self, func, param_nodes): 5310c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Find the final parameter.""" 5320c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param = func.get_param(self.name) 5330c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_index = -1 5340c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5350c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # the described param is not in the final function 5360c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not param: 5370c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # search the template parameters 5380c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu node, index = self._search_param_node(param_nodes) 5390c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not node: 5400c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("invalid desc %s in %s" % 5410c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu (self.name, func.name)) 5420c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5430c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # a named parameter of a vector 5440c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if index >= 0: 5450c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param = func.get_param(node.prop("name")) 5460c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param_index = index 5470c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif node.name == "vector": 5480c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # must be an expanded vector, check its size 5490c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if self.size_str and self.size_str.isdigit(): 5500c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu size = int(self.size_str) 5510c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu expanded_size = func.param_node_size(node) 5520c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if size != expanded_size: 5530c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (False, None, -1) 5540c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # otherwise, it is a valid, but no-op, description 5550c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5560c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return (True, param, param_index) 5570c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5580c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu def validate(self, func, param_nodes): 5590c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu """Validate a description against certain function.""" 5600c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if self.checker.switches and not self.values: 5610c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("no valid values for %s" % self.name) 5620c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5630c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu valid, param, param_index = self._find_final(func, param_nodes) 5640c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not valid: 5650c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return False 5660c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5670c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # the description is valid, but the param is gone 5680c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # mark it no-op so that it will be skipped 5690c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not param: 5700c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self._is_noop = True 5710c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return True 5720c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5730c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if param.is_vector: 5740c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # if param was known, this should have been done in __init__ 5750c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if self._has_enum: 5760c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.size_str = "1" 5770c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # size mismatch 5780c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if (param.size and self.size_str and self.size_str.isdigit() and 5790c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu param.size != int(self.size_str)): 5800c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return False 5810c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu elif self.size_str: 5820c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # only vector accepts vector_size 5830c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu raise SpecError("vector_size is invalid for %s" % param.name) 5840c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5850c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu if not self.checker.validate(func, param_nodes): 5860c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return False 5870c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5880c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu # update the description 5890c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.name = param.name 5900c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu self.index = param_index 5910c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5920c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu return True 5930c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5940c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5950c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wudef main(): 5960c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu import libxml2 5970c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 5980c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu filename = "APIspec.xml" 5990c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu apinames = ["GLES1.1", "GLES2.0"] 6000c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 6010c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu doc = libxml2.readFile(filename, None, 6020c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu libxml2.XML_PARSE_DTDLOAD + 6030c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu libxml2.XML_PARSE_DTDVALID + 6040c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu libxml2.XML_PARSE_NOBLANKS) 6050c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 6060c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu spec = Spec(doc) 6070c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu impl = spec.get_impl() 6080c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu for apiname in apinames: 6090c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu spec.get_api(apiname) 6100c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 6110c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu doc.freeDoc() 6120c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 6130c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu print "%s is successfully parsed" % filename 6140c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 6150c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu 6160c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wuif __name__ == "__main__": 6170c1a7bbe0d0c6727a432890164032188787e7e26Chia-I Wu main() 618