diff options
Diffstat (limited to 'mesalib/src/mesa/main/APIspec.py')
-rw-r--r-- | mesalib/src/mesa/main/APIspec.py | 617 |
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() |