aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/mesa/main/APIspec.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src/mesa/main/APIspec.py')
-rw-r--r--mesalib/src/mesa/main/APIspec.py617
1 files changed, 0 insertions, 617 deletions
diff --git a/mesalib/src/mesa/main/APIspec.py b/mesalib/src/mesa/main/APIspec.py
deleted file mode 100644
index 6947f7301..000000000
--- a/mesalib/src/mesa/main/APIspec.py
+++ /dev/null
@@ -1,617 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (C) 2009 Chia-I Wu <olv@0xlab.org>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# on the rights to use, copy, modify, merge, publish, distribute, sub
-# license, and/or sell copies of the Software, and to permit persons to whom
-# the Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice (including the next
-# paragraph) shall be included in all copies or substantial portions of the
-# Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-"""
-A parser for APIspec.
-"""
-
-class SpecError(Exception):
- """Error in the spec file."""
-
-
-class Spec(object):
- """A Spec is an abstraction of the API spec."""
-
- def __init__(self, doc):
- self.doc = doc
-
- self.spec_node = doc.getRootElement()
- self.tmpl_nodes = {}
- self.api_nodes = {}
- self.impl_node = None
-
- # parse <apispec>
- node = self.spec_node.children
- while node:
- if node.type == "element":
- if node.name == "template":
- self.tmpl_nodes[node.prop("name")] = node
- elif node.name == "api":
- self.api_nodes[node.prop("name")] = node
- else:
- raise SpecError("unexpected node %s in apispec" %
- node.name)
- node = node.next
-
- # find an implementation
- for name, node in self.api_nodes.iteritems():
- if node.prop("implementation") == "true":
- self.impl_node = node
- break
- if not self.impl_node:
- raise SpecError("unable to find an implementation")
-
- def get_impl(self):
- """Return the implementation."""
- return API(self, self.impl_node)
-
- def get_api(self, name):
- """Return an API."""
- return API(self, self.api_nodes[name])
-
-
-class API(object):
- """An API consists of categories and functions."""
-
- def __init__(self, spec, api_node):
- self.name = api_node.prop("name")
- self.is_impl = (api_node.prop("implementation") == "true")
-
- self.categories = []
- self.functions = []
-
- # parse <api>
- func_nodes = []
- node = api_node.children
- while node:
- if node.type == "element":
- if node.name == "category":
- cat = node.prop("name")
- self.categories.append(cat)
- elif node.name == "function":
- func_nodes.append(node)
- else:
- raise SpecError("unexpected node %s in api" % node.name)
- node = node.next
-
- # realize functions
- for func_node in func_nodes:
- tmpl_node = spec.tmpl_nodes[func_node.prop("template")]
- try:
- func = Function(tmpl_node, func_node, self.is_impl,
- self.categories)
- except SpecError, e:
- func_name = func_node.prop("name")
- raise SpecError("failed to parse %s: %s" % (func_name, e))
- self.functions.append(func)
-
- def match(self, func, conversions={}):
- """Find a matching function in the API."""
- match = None
- need_conv = False
- for f in self.functions:
- matched, conv = f.match(func, conversions)
- if matched:
- match = f
- need_conv = conv
- # exact match
- if not need_conv:
- break
- return (match, need_conv)
-
-
-class Function(object):
- """Parse and realize a <template> node."""
-
- def __init__(self, tmpl_node, func_node, force_skip_desc=False, categories=[]):
- self.tmpl_name = tmpl_node.prop("name")
- self.direction = tmpl_node.prop("direction")
-
- self.name = func_node.prop("name")
- self.prefix = func_node.prop("default_prefix")
- self.is_external = (func_node.prop("external") == "true")
-
- if force_skip_desc:
- self._skip_desc = True
- else:
- self._skip_desc = (func_node.prop("skip_desc") == "true")
-
- self._categories = categories
-
- # these attributes decide how the template is realized
- self._gltype = func_node.prop("gltype")
- if func_node.hasProp("vector_size"):
- self._vector_size = int(func_node.prop("vector_size"))
- else:
- self._vector_size = 0
- self._expand_vector = (func_node.prop("expand_vector") == "true")
-
- self.return_type = "void"
- param_nodes = []
-
- # find <proto>
- proto_node = tmpl_node.children
- while proto_node:
- if proto_node.type == "element" and proto_node.name == "proto":
- break
- proto_node = proto_node.next
- if not proto_node:
- raise SpecError("no proto")
- # and parse it
- node = proto_node.children
- while node:
- if node.type == "element":
- if node.name == "return":
- self.return_type = node.prop("type")
- elif node.name == "param" or node.name == "vector":
- if self.support_node(node):
- # make sure the node is not hidden
- if not (self._expand_vector and
- (node.prop("hide_if_expanded") == "true")):
- param_nodes.append(node)
- else:
- raise SpecError("unexpected node %s in proto" % node.name)
- node = node.next
-
- self._init_params(param_nodes)
- self._init_descs(tmpl_node, param_nodes)
-
- def __str__(self):
- return "%s %s%s(%s)" % (self.return_type, self.prefix, self.name,
- self.param_string(True))
-
- def _init_params(self, param_nodes):
- """Parse and initialize parameters."""
- self.params = []
-
- for param_node in param_nodes:
- size = self.param_node_size(param_node)
- # when no expansion, vector is just like param
- if param_node.name == "param" or not self._expand_vector:
- param = Parameter(param_node, self._gltype, size)
- self.params.append(param)
- continue
-
- if not size or size > param_node.lsCountNode():
- raise SpecError("could not expand %s with unknown or "
- "mismatch sizes" % param.name)
-
- # expand the vector
- expanded_params = []
- child = param_node.children
- while child:
- if (child.type == "element" and child.name == "param" and
- self.support_node(child)):
- expanded_params.append(Parameter(child, self._gltype))
- if len(expanded_params) == size:
- break
- child = child.next
- # just in case that lsCountNode counts unknown nodes
- if len(expanded_params) < size:
- raise SpecError("not enough named parameters")
-
- self.params.extend(expanded_params)
-
- def _init_descs(self, tmpl_node, param_nodes):
- """Parse and initialize parameter descriptions."""
- self.checker = Checker()
- if self._skip_desc:
- return
-
- node = tmpl_node.children
- while node:
- if node.type == "element" and node.name == "desc":
- if self.support_node(node):
- # parse <desc>
- desc = Description(node, self._categories)
- self.checker.add_desc(desc)
- node = node.next
-
- self.checker.validate(self, param_nodes)
-
- def support_node(self, node):
- """Return true if a node is in the supported category."""
- return (not node.hasProp("category") or
- node.prop("category") in self._categories)
-
- def get_param(self, name):
- """Return the named parameter."""
- for param in self.params:
- if param.name == name:
- return param
- return None
-
- def param_node_size(self, param):
- """Return the size of a vector."""
- if param.name != "vector":
- return 0
-
- size = param.prop("size")
- if size.isdigit():
- size = int(size)
- else:
- size = 0
- if not size:
- size = self._vector_size
- if not size and self._expand_vector:
- # return the number of named parameters
- size = param.lsCountNode()
- return size
-
- def param_string(self, declaration):
- """Return the C code of the parameters."""
- args = []
- if declaration:
- for param in self.params:
- sep = "" if param.type.endswith("*") else " "
- args.append("%s%s%s" % (param.type, sep, param.name))
- if not args:
- args.append("void")
- else:
- for param in self.params:
- args.append(param.name)
- return ", ".join(args)
-
- def match(self, other, conversions={}):
- """Return true if the functions match, probably with a conversion."""
- if (self.tmpl_name != other.tmpl_name or
- self.return_type != other.return_type or
- len(self.params) != len(other.params)):
- return (False, False)
-
- need_conv = False
- for i in xrange(len(self.params)):
- src = other.params[i]
- dst = self.params[i]
- if (src.is_vector != dst.is_vector or src.size != dst.size):
- return (False, False)
- if src.type != dst.type:
- if dst.base_type() in conversions.get(src.base_type(), []):
- need_conv = True
- else:
- # unable to convert
- return (False, False)
-
- return (True, need_conv)
-
-
-class Parameter(object):
- """A parameter of a function."""
-
- def __init__(self, param_node, gltype=None, size=0):
- self.is_vector = (param_node.name == "vector")
-
- self.name = param_node.prop("name")
- self.size = size
-
- type = param_node.prop("type")
- if gltype:
- type = type.replace("GLtype", gltype)
- elif type.find("GLtype") != -1:
- raise SpecError("parameter %s has unresolved type" % self.name)
-
- self.type = type
-
- def base_type(self):
- """Return the base GL type by stripping qualifiers."""
- return [t for t in self.type.split(" ") if t.startswith("GL")][0]
-
-
-class Checker(object):
- """A checker is the collection of all descriptions on the same level.
- Descriptions of the same parameter are concatenated.
- """
-
- def __init__(self):
- self.switches = {}
- self.switch_constants = {}
-
- def add_desc(self, desc):
- """Add a description."""
- # TODO allow index to vary
- const_attrs = ["index", "error", "convert", "size_str"]
- if desc.name not in self.switches:
- self.switches[desc.name] = []
- self.switch_constants[desc.name] = {}
- for attr in const_attrs:
- self.switch_constants[desc.name][attr] = None
-
- # some attributes, like error code, should be the same for all descs
- consts = self.switch_constants[desc.name]
- for attr in const_attrs:
- if getattr(desc, attr) is not None:
- if (consts[attr] is not None and
- consts[attr] != getattr(desc, attr)):
- raise SpecError("mismatch %s for %s" % (attr, desc.name))
- consts[attr] = getattr(desc, attr)
-
- self.switches[desc.name].append(desc)
-
- def validate(self, func, param_nodes):
- """Validate the checker against a function."""
- tmp = Checker()
-
- for switch in self.switches.itervalues():
- valid_descs = []
- for desc in switch:
- if desc.validate(func, param_nodes):
- valid_descs.append(desc)
- # no possible values
- if not valid_descs:
- return False
- for desc in valid_descs:
- if not desc._is_noop:
- tmp.add_desc(desc)
-
- self.switches = tmp.switches
- self.switch_constants = tmp.switch_constants
- return True
-
- def flatten(self, name=None):
- """Return a flat list of all descriptions of the named parameter."""
- flat_list = []
- for switch in self.switches.itervalues():
- for desc in switch:
- if not name or desc.name == name:
- flat_list.append(desc)
- flat_list.extend(desc.checker.flatten(name))
- return flat_list
-
- def always_check(self, name):
- """Return true if the parameter is checked in all possible pathes."""
- if name in self.switches:
- return True
-
- # a param is always checked if any of the switch always checks it
- for switch in self.switches.itervalues():
- # a switch always checks it if all of the descs always check it
- always = True
- for desc in switch:
- if not desc.checker.always_check(name):
- always = False
- break
- if always:
- return True
- return False
-
- def _c_switch(self, name, indent="\t"):
- """Output C switch-statement for the named parameter, for debug."""
- switch = self.switches.get(name, [])
- # make sure there are valid values
- need_switch = False
- for desc in switch:
- if desc.values:
- need_switch = True
- if not need_switch:
- return []
-
- stmts = []
- var = switch[0].name
- if switch[0].index >= 0:
- var += "[%d]" % switch[0].index
- stmts.append("switch (%s) { /* assume GLenum */" % var)
-
- for desc in switch:
- if desc.values:
- for val in desc.values:
- stmts.append("case %s:" % val)
- for dep_name in desc.checker.switches.iterkeys():
- dep_stmts = [indent + s for s in desc.checker._c_switch(dep_name, indent)]
- stmts.extend(dep_stmts)
- stmts.append(indent + "break;")
-
- stmts.append("default:")
- stmts.append(indent + "ON_ERROR(%s);" % switch[0].error);
- stmts.append(indent + "break;")
- stmts.append("}")
-
- return stmts
-
- def dump(self, indent="\t"):
- """Dump the descriptions in C code."""
- stmts = []
- for name in self.switches.iterkeys():
- c_switch = self._c_switch(name)
- print "\n".join(c_switch)
-
-
-class Description(object):
- """A description desribes a parameter and its relationship with other
- parameters.
- """
-
- def __init__(self, desc_node, categories=[]):
- self._categories = categories
- self._is_noop = False
-
- self.name = desc_node.prop("name")
- self.index = -1
-
- self.error = desc_node.prop("error") or "GL_INVALID_ENUM"
- # vector_size may be C code
- self.size_str = desc_node.prop("vector_size")
-
- self._has_enum = False
- self.values = []
- dep_nodes = []
-
- # parse <desc>
- valid_names = ["value", "range", "desc"]
- node = desc_node.children
- while node:
- if node.type == "element":
- if node.name in valid_names:
- # ignore nodes that require unsupported categories
- if (node.prop("category") and
- node.prop("category") not in self._categories):
- node = node.next
- continue
- else:
- raise SpecError("unexpected node %s in desc" % node.name)
-
- if node.name == "value":
- val = node.prop("name")
- if not self._has_enum and val.startswith("GL_"):
- self._has_enum = True
- self.values.append(val)
- elif node.name == "range":
- first = int(node.prop("from"))
- last = int(node.prop("to"))
- base = node.prop("base") or ""
- if not self._has_enum and base.startswith("GL_"):
- self._has_enum = True
- # expand range
- for i in xrange(first, last + 1):
- self.values.append("%s%d" % (base, i))
- else: # dependent desc
- dep_nodes.append(node)
- node = node.next
-
- # default to convert if there is no enum
- self.convert = not self._has_enum
- if desc_node.hasProp("convert"):
- self.convert = (desc_node.prop("convert") == "true")
-
- self._init_deps(dep_nodes)
-
- def _init_deps(self, dep_nodes):
- """Parse and initialize dependents."""
- self.checker = Checker()
-
- for dep_node in dep_nodes:
- # recursion!
- dep = Description(dep_node, self._categories)
- self.checker.add_desc(dep)
-
- def _search_param_node(self, param_nodes, name=None):
- """Search the template parameters for the named node."""
- param_node = None
- param_index = -1
-
- if not name:
- name = self.name
- for node in param_nodes:
- if name == node.prop("name"):
- param_node = node
- elif node.name == "vector":
- child = node.children
- idx = 0
- while child:
- if child.type == "element" and child.name == "param":
- if name == child.prop("name"):
- param_node = node
- param_index = idx
- break
- idx += 1
- child = child.next
- if param_node:
- break
- return (param_node, param_index)
-
- def _find_final(self, func, param_nodes):
- """Find the final parameter."""
- param = func.get_param(self.name)
- param_index = -1
-
- # the described param is not in the final function
- if not param:
- # search the template parameters
- node, index = self._search_param_node(param_nodes)
- if not node:
- raise SpecError("invalid desc %s in %s" %
- (self.name, func.name))
-
- # a named parameter of a vector
- if index >= 0:
- param = func.get_param(node.prop("name"))
- param_index = index
- elif node.name == "vector":
- # must be an expanded vector, check its size
- if self.size_str and self.size_str.isdigit():
- size = int(self.size_str)
- expanded_size = func.param_node_size(node)
- if size != expanded_size:
- return (False, None, -1)
- # otherwise, it is a valid, but no-op, description
-
- return (True, param, param_index)
-
- def validate(self, func, param_nodes):
- """Validate a description against certain function."""
- if self.checker.switches and not self.values:
- raise SpecError("no valid values for %s" % self.name)
-
- valid, param, param_index = self._find_final(func, param_nodes)
- if not valid:
- return False
-
- # the description is valid, but the param is gone
- # mark it no-op so that it will be skipped
- if not param:
- self._is_noop = True
- return True
-
- if param.is_vector:
- # if param was known, this should have been done in __init__
- if self._has_enum:
- self.size_str = "1"
- # size mismatch
- if (param.size and self.size_str and self.size_str.isdigit() and
- param.size != int(self.size_str)):
- return False
- elif self.size_str:
- # only vector accepts vector_size
- raise SpecError("vector_size is invalid for %s" % param.name)
-
- if not self.checker.validate(func, param_nodes):
- return False
-
- # update the description
- self.name = param.name
- self.index = param_index
-
- return True
-
-
-def main():
- import libxml2
-
- filename = "APIspec.xml"
- apinames = ["GLES1.1", "GLES2.0"]
-
- doc = libxml2.readFile(filename, None,
- libxml2.XML_PARSE_DTDLOAD +
- libxml2.XML_PARSE_DTDVALID +
- libxml2.XML_PARSE_NOBLANKS)
-
- spec = Spec(doc)
- impl = spec.get_impl()
- for apiname in apinames:
- spec.get_api(apiname)
-
- doc.freeDoc()
-
- print "%s is successfully parsed" % filename
-
-
-if __name__ == "__main__":
- main()