Mammoth update to the Python code generator scripts that live in
[mesa.git] / src / mesa / glapi / gl_XML.py
index 1771975e843a228031cdff2a18ed3b0e73ed4bad..e4de4cacdd681aa1b6fcd06f33a23d1d61ef9d12 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python
 
 # (C) Copyright IBM Corporation 2004, 2005
 # All Rights Reserved.
 # Authors:
 #    Ian Romanick <idr@us.ibm.com>
 
-from xml.sax import saxutils
-from xml.sax import make_parser
-from xml.sax.handler import feature_namespaces
+import libxml2
+import re, sys, string
+import typeexpr
 
-import re
 
-class glItem:
-       """Generic class on which all other API entity types are based."""
+def parse_GL_API( file_name, factory = None ):
+       doc = libxml2.readFile( file_name, None, libxml2.XML_PARSE_XINCLUDE + libxml2.XML_PARSE_NOBLANKS + libxml2.XML_PARSE_DTDVALID + libxml2.XML_PARSE_DTDATTR + libxml2.XML_PARSE_DTDLOAD + libxml2.XML_PARSE_NOENT )
+       ret = doc.xincludeProcess()
 
-       def __init__(self, tag_name, name, context):
-               self.name = name
-               self.category = context.get_category_define()
-               self.context = context
-               self.tag_name = tag_name
-               
-               context.append(tag_name, self)
-               return
+       if not factory:
+               factory = gl_item_factory()
+
+       api = factory.create_item( "api", None, None )
+       api.process_element( doc )
+
+       doc.freeDoc()
+
+       return api
+
+
+def is_attr_true( element, name ):
+       """Read a name value from an element's attributes.
        
-       def startElement(self, name, attrs):
-               """Generic startElement handler.
-               
-               The startElement handler is called for all elements except
-               the one that starts the object.  For a foo element, the
-               XML "<foo><bar/></foo>" would cause the startElement handler
-               to be called once, but the endElement handler would be called
-               twice."""
-               return
+       The value read from the attribute list must be either 'true' or
+       'false'.  If the value is 'false', zero will be returned.  If the
+       value is 'true', non-zero will be returned.  An exception will be
+       raised for any other value."""
+
+       value = element.nsProp( name, None )
+       if value == "true":
+               return 1
+       elif value == "false":
+               return 0
+       else:
+               raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
+
+
+class gl_print_base:
+       """Base class of all API pretty-printers.
+
+       In the model-view-controller pattern, this is the view.  Any derived
+       class will want to over-ride the printBody, printRealHader, and
+       printRealFooter methods.  Some derived classes may want to over-ride
+       printHeader and printFooter, or even Print (though this is unlikely).
+       """
+
+       def __init__(self):
+               # Name of the script that is generating the output file.
+               # Every derived class should set this to the name of its
+               # source file.
+
+               self.name = "a"
+
+
+               # License on the *generated* source file.  This may differ
+               # from the license on the script that is generating the file.
+               # Every derived class should set this to some reasonable
+               # value.
+               #
+               # See license.py for an example of a reasonable value.
 
-       def endElement(self, name):
-               """Generic endElement handler.
+               self.license = "The license for this file is unspecified."
 
-               Generic endElement handler.    Returns 1 if the tag containing
-               the object is complete.  Otherwise 0 is returned.  All
-               derived class endElement handlers should call this method.  If
-               the name of the ending tag is the same as the tag that
-               started this object, the object is assumed to be complete.
                
-               This fails if a tag can contain another tag with the same
-               name.  The XML "<foo><foo/><bar/></foo>" would fail.  The
-               object would end before the bar tag was processed.
+               # The header_tag is the name of the C preprocessor define
+               # used to prevent multiple inclusion.  Typically only
+               # generated C header files need this to be set.  Setting it
+               # causes code to be generated automatically in printHeader
+               # and printFooter.
+
+               self.header_tag = None
+
                
-               The endElement handler is called for every end element
-               associated with an object, even the element that started the
-               object.  See the description of startElement an example."""
+               # List of file-private defines that must be undefined at the
+               # end of the file.  This can be used in header files to define
+               # names for use in the file, then undefine them at the end of
+               # the header file.
 
-               if name == self.tag_name:
-                       return 1
-               else:
-                       return 0
+               self.undef_list = []
+               return
+
+
+       def Print(self, api):
+               self.printHeader()
+               self.printBody(api)
+               self.printFooter()
+               return
+
+
+       def printHeader(self):
+               """Print the header associated with all files and call the printRealHeader method."""
+
+               print '/* DO NOT EDIT - This file generated automatically by %s script */' \
+                       % (self.name)
+               print ''
+               print '/*'
+               print ' * ' + self.license.replace('\n', '\n * ')
+               print ' */'
+               print ''
+               if self.header_tag:
+                   print '#if !defined( %s )' % (self.header_tag)
+                   print '#  define %s' % (self.header_tag)
+                   print ''
+               self.printRealHeader();
+               return
+
+
+       def printFooter(self):
+               """Print the header associated with all files and call the printRealFooter method."""
+
+               self.printRealFooter()
+
+               if self.undef_list:
+                       print ''
+                       for u in self.undef_list:
+                               print "#  undef %s" % (u)
+
+               if self.header_tag:
+                       print ''
+                       print '#endif /* !defined( %s ) */' % (self.header_tag)
+
+
+       def printRealHeader(self):
+               """Print the "real" header for the created file.
+
+               In the base class, this function is empty.  All derived
+               classes should over-ride this function."""
+               return
+
+
+       def printRealFooter(self):
+               """Print the "real" footer for the created file.
+
+               In the base class, this function is empty.  All derived
+               classes should over-ride this function."""
+               return
 
-       def get_category_define(self):
-               return self.category
 
+       def printPure(self):
+               """Conditionally define `PURE' function attribute.
+
+               Conditionally defines a preprocessor macro `PURE' that wraps
+               GCC's `pure' function attribute.  The conditional code can be
+               easilly adapted to other compilers that support a similar
+               feature.
+
+               The name is also added to the file's undef_list.
+               """
+               self.undef_list.append("PURE")
+               print """#  if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#    define PURE __attribute__((pure))
+#  else
+#    define PURE
+#  endif"""
+               return
+
+
+       def printFastcall(self):
+               """Conditionally define `FASTCALL' function attribute.
+
+               Conditionally defines a preprocessor macro `FASTCALL' that
+               wraps GCC's `fastcall' function attribute.  The conditional
+               code can be easilly adapted to other compilers that support a
+               similar feature.
+
+               The name is also added to the file's undef_list.
+               """
+
+               self.undef_list.append("FASTCALL")
+               print """#  if defined(__i386__) && defined(__GNUC__)
+#    define FASTCALL __attribute__((fastcall))
+#  else
+#    define FASTCALL
+#  endif"""
+               return
+
+
+       def printVisibility(self, S, s):
+               """Conditionally define visibility function attribute.
+
+               Conditionally defines a preprocessor macro name S that wraps
+               GCC's visibility function attribute.  The visibility used is
+               the parameter s.  The conditional code can be easilly adapted
+               to other compilers that support a similar feature.
+
+               The name is also added to the file's undef_list.
+               """
+
+               self.undef_list.append(S)
+               print """#  if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+#    define %s  __attribute__((visibility("%s")))
+#  else
+#    define %s
+#  endif""" % (S, s, S)
+               return
+
+
+       def printNoinline(self):
+               """Conditionally define `NOINLINE' function attribute.
+
+               Conditionally defines a preprocessor macro `NOINLINE' that
+               wraps GCC's `noinline' function attribute.  The conditional
+               code can be easilly adapted to other compilers that support a
+               similar feature.
+
+               The name is also added to the file's undef_list.
+               """
+
+               self.undef_list.append("NOINLINE")
+               print """#  if defined(__GNUC__)
+#    define NOINLINE __attribute__((noinline))
+#  else
+#    define NOINLINE
+#  endif"""
+               return
+
+
+       def printHaveAlias(self):
+               """Conditionally define `HAVE_ALIAS'.
+
+               Conditionally defines a preprocessor macro `HAVE_ALIAS'.  The
+               existance of this macro can be used to determine whether or
+               not GCC's alias function attribute can be used.
+
+               The name is also added to the file's undef_list.
+               """
+
+               self.undef_list.append("HAVE_ALIAS")
+               print """#  if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#    define HAVE_ALIAS
+#  endif"""
+               return
 
-class glEnum( glItem ):
-       """Subclass of glItem for representing GL enumerants.
+
+def real_function_name(element):
+       name = element.nsProp( "name", None )
+       alias = element.nsProp( "alias", None )
        
-       This class is not complete, and is not really used yet."""
+       if alias:
+               return alias
+       else:
+               return name
+
 
-       def __init__(self, context, name, attrs):
-               self.value = int(attrs.get('value', "0x0000"), 0)
+class gl_item:
+       def __init__(self, element, context):
+               self.context = context
 
-               enum_name = "GL_" + attrs.get('name', None)
-               glItem.__init__(self, name, enum_name, context)
+               self.name = element.nsProp( "name", None )
 
-               temp = attrs.get('count', None)
-               if temp == None:
-                       self.default_count = 0
+               c = element.parent.nsProp( "name", None )
+               if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
+                       self.category = "GL_VERSION_" + c.replace(".", "_")
                else:
-                       try:
-                               c = int(temp)
-                       except Exception,e:
-                               raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
+                       self.category = c
 
-                       self.default_count = c
                return
 
 
-       def process_attributes(self, attrs):
-               name = attrs.get('name', None)
+class gl_type( gl_item ):
+       def __init__(self, element, context):
+               gl_item.__init__(self, element, context)
+               self.size = int( element.nsProp( "size", None ), 0 )
+
+               te = typeexpr.type_expression( None )
+               tn = typeexpr.type_node()
+               tn.size = int( element.nsProp( "size", None ), 0 )
+               tn.integer = not is_attr_true( element, "float" )
+               tn.unsigned = is_attr_true( element, "unsigned" )
+               tn.name = "GL" + self.name
+               te.set_base_type_node( tn )
+
+               self.type_expr = te
+               return
+       
 
-               temp = attrs.get('count', None)
-               if temp == None:
-                       c = self.default_count
+       def get_type_expression(self):
+               return self.type_expr
+
+
+class gl_enum( gl_item ):
+       def __init__(self, element, context):
+               gl_item.__init__(self, element, context)
+               self.value = int( element.nsProp( "value", None ), 0 )
+
+               temp = element.nsProp( "count", None )
+               if not temp or temp == "?":
+                       self.default_count = -1
                else:
                        try:
                                c = int(temp)
                        except Exception,e:
                                raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
 
-               mode_str = attrs.get('mode', "set")
-               if mode_str == "set":
-                       mode = 1
-               elif mode_str == "get":
-                       mode = 0
-               else:
-                       raise RuntimeError("Invalid mode '%s' for function '%s' in enum '%s'." % (mode_str, self.context.name, self.name))
+                       self.default_count = c
+
+               return
 
-               return [name, c, mode]
 
+       def priority(self):
+               """Calculate a 'priority' for this enum name.
+               
+               When an enum is looked up by number, there may be many
+               possible names, but only one is the 'prefered' name.  The
+               priority is used to select which name is the 'best'.
+
+               Highest precedence is given to core GL name.  ARB extension
+               names have the next highest, followed by EXT extension names.
+               Vendor extension names are the lowest.
+               """
 
-class glType( glItem ):
-       """Subclass of glItem for representing GL types."""
+               if self.name.endswith( "_BIT" ):
+                       bias = 1
+               else:
+                       bias = 0
+
+               if self.category.startswith( "GL_VERSION_" ):
+                       priority = 0
+               elif self.category.startswith( "GL_ARB_" ):
+                       priority = 2
+               elif self.category.startswith( "GL_EXT_" ):
+                       priority = 4
+               else:
+                       priority = 6
 
-       def __init__(self, context, name, attrs):
-               self.size = int(attrs.get('size', "0"))
-               self.glx_name = attrs.get('glx_name', "")
+               return priority + bias
 
-               type_name = "GL" + attrs.get('name', None)
-               glItem.__init__(self, name, type_name, context)
 
 
-class glParameter( glItem ):
-       """Parameter of a glFunction."""
-       p_type = None
-       p_type_string = ""
-       p_count = 0
-       p_count_parameters = None
-       counter = None
-       is_output = 0
-       is_counter = 0
-       is_pointer = 0
+class gl_parameter:
+       def __init__(self, element, context):
+               self.name = element.nsProp( "name", None )
 
-       def __init__(self, context, name, attrs):
-               p_name = attrs.get('name', None)
-               self.p_type_string = attrs.get('type', None)
-               self.p_count_parameters = attrs.get('variable_param', None)
+               ts = element.nsProp( "type", None )
+               self.type_expr = typeexpr.type_expression( ts, context )
 
-               if self.p_count_parameters:
-                       temp = self.p_count_parameters.replace( ' ', '' )
-                       self.count_parameter_list = temp.split( ',' )
+               temp = element.nsProp( "variable_param", None )
+               if temp:
+                       self.count_parameter_list = temp.split( ' ' )
                else:
                        self.count_parameter_list = []
 
-               self.p_type = context.context.find_type(self.p_type_string)
-               if self.p_type == None:
-                       raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
-
-
                # The count tag can be either a numeric string or the name of
                # a variable.  If it is the name of a variable, the int(c)
                # statement will throw an exception, and the except block will
                # take over.
 
-               c = attrs.get('count', "0")
+               c = element.nsProp( "count", None )
                try: 
-                       self.p_count = int(c)
+                       count = int(c)
+                       self.count = count
                        self.counter = None
                except Exception,e:
-                       self.p_count = 0
+                       count = 1
+                       self.count = 0
                        self.counter = c
+               
+               self.count_scale = int(element.nsProp( "count_scale", None ))
 
-               if attrs.get('counter', "false") == "true":
-                       self.is_counter = 1
-               else:
-                       self.is_counter = 0
+               elements = (count * self.count_scale)
+               if elements == 1:
+                       elements = 0
+
+               #if ts == "GLdouble":
+               #       print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
+               #       print '/* # elements = %u */' % (elements)
+               self.type_expr.set_elements( elements )
+               #if ts == "GLdouble":
+               #       print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
+
+               self.is_counter = is_attr_true( element, 'counter' )
+               self.is_output  = is_attr_true( element, 'output' )
 
-               if attrs.get('output', "false") == "true":
-                       self.is_output = 1
-               else:
-                       self.is_output = 0
 
-                       
                # Pixel data has special parameters.
 
-               self.width      = attrs.get('img_width',  None)
-               self.height     = attrs.get('img_height', None)
-               self.depth      = attrs.get('img_depth',  None)
-               self.extent     = attrs.get('img_extent', None)
+               self.width      = element.nsProp('img_width',  None)
+               self.height     = element.nsProp('img_height', None)
+               self.depth      = element.nsProp('img_depth',  None)
+               self.extent     = element.nsProp('img_extent', None)
 
-               self.img_xoff   = attrs.get('img_xoff',   None)
-               self.img_yoff   = attrs.get('img_yoff',   None)
-               self.img_zoff   = attrs.get('img_zoff',   None)
-               self.img_woff   = attrs.get('img_woff',   None)
+               self.img_xoff   = element.nsProp('img_xoff',   None)
+               self.img_yoff   = element.nsProp('img_yoff',   None)
+               self.img_zoff   = element.nsProp('img_zoff',   None)
+               self.img_woff   = element.nsProp('img_woff',   None)
 
-               self.img_format = attrs.get('img_format', None)
-               self.img_type   = attrs.get('img_type',   None)
-               self.img_target = attrs.get('img_target', None)
+               self.img_format = element.nsProp('img_format', None)
+               self.img_type   = element.nsProp('img_type',   None)
+               self.img_target = element.nsProp('img_target', None)
 
-               pad = attrs.get('img_pad_dimensions', "false")
-               if pad == "true":
-                       self.img_pad_dimensions = 1
-               else:
-                       self.img_pad_dimensions = 0
+               self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
+               self.img_null_flag      = is_attr_true( element, 'img_null_flag' )
+               self.img_send_null      = is_attr_true( element, 'img_send_null' )
 
+               return
 
-               null_flag = attrs.get('img_null_flag', "false")
-               if null_flag == "true":
-                       self.img_null_flag = 1
-               else:
-                       self.img_null_flag = 0
 
-               send_null = attrs.get('img_send_null', "false")
-               if send_null == "true":
-                       self.img_send_null = 1
-               else:
-                       self.img_send_null = 0
+       def compatible(self, other):
+               return 1
+
 
+       def is_array(self):
+               return self.is_pointer()
+
+
+       def is_pointer(self):
+               return self.type_expr.is_pointer()
 
 
-               if self.p_count > 0 or self.counter or self.p_count_parameters:
-                       has_count = 1
+       def is_image(self):
+               if self.width:
+                       return 1
                else:
-                       has_count = 0
+                       return 0
 
 
-               # If there is a * anywhere in the parameter's type, then it
-               # is a pointer.
+       def is_variable_length(self):
+               return len(self.count_parameter_list) or self.counter
 
-               if re.compile("[*]").search(self.p_type_string):
-                       # We could do some other validation here.  For
-                       # example, an output parameter should not be const,
-                       # but every non-output parameter should.
 
-                       self.is_pointer = 1;
+       def is_64_bit(self):
+               count = self.type_expr.get_element_count()
+               if count:
+                       if (self.size() / count) == 8:
+                               return 1
                else:
-                       # If a parameter is not a pointer, then there cannot
-                       # be an associated count (either fixed size or
-                       # variable) and the parameter cannot be an output.
+                       if self.size() == 8:
+                               return 1
 
-                       if has_count or self.is_output:
-                               raise RuntimeError("Non-pointer type has count or is output.")
-                       self.is_pointer = 0;
+               return 0
 
-               glItem.__init__(self, name, p_name, context)
-               return
 
+       def string(self):
+               return self.type_expr.original_string + " " + self.name
 
-       def is_variable_length_array(self):
-               """Determine if a parameter is a variable length array.
-               
-               A parameter is considered to be a variable length array if
-               its size depends on the value of another parameter that is
-               an enumerant.  The params parameter to glTexEnviv is an
-               example of a variable length array parameter.  Arrays whose
-               size depends on a count variable, such as the lists parameter
-               to glCallLists, are not variable length arrays in this
-               sense."""
 
-               return self.p_count_parameters or self.counter or self.width
+       def type_string(self):
+               return self.type_expr.original_string
 
 
-       def is_array(self):
-               return self.is_pointer
+       def get_base_type_string(self):
+               return self.type_expr.get_base_name()
 
 
-       def count_string(self):
-               """Return a string representing the number of items
-               
-               Returns a string representing the number of items in a
-               parameter.  For scalar types this will always be "1".  For
-               vector types, it will depend on whether or not it is a
-               fixed length vector (like the parameter of glVertex3fv),
-               a counted length (like the vector parameter of
-               glDeleteTextures), or a general variable length vector."""
-
-               if self.is_array():
-                       if self.p_count_parameters != None:
-                               return "compsize"
-                       elif self.counter != None:
-                               return self.counter
-                       else:
-                               return str(self.p_count)
-               else:
-                       return "1"
+       def get_dimensions(self):
+               if not self.width:
+                       return [ 0, "0", "0", "0", "0" ]
 
+               dim = 1
+               w = self.width
+               h = "1"
+               d = "1"
+               e = "1"
 
-       def size(self):
-               if self.p_count_parameters or self.counter or self.width or self.is_output:
-                       return 0
-               elif self.p_count == 0:
-                       return self.p_type.size
-               else:
-                       return self.p_type.size * self.p_count
+               if self.height:
+                       dim = 2
+                       h = self.height
 
-       def size_string(self):
-               s = self.size()
-               if s == 0:
-                       a_prod = "compsize"
-                       b_prod = self.p_type.size
-
-                       # Handle functions like glCompressedTexImage2D that
-                       # have a counted 'void *' parameter.
-
-                       if b_prod == 0: b_prod = 1
-
-                       if self.p_count_parameters == None and self.counter != None:
-                               a_prod = self.counter
-                       elif self.p_count_parameters != None and self.counter == None:
-                               pass
-                       elif self.p_count_parameters != None and self.counter != None:
-                               b_prod = self.counter
-                       elif self.width:
-                               return "compsize"
-                       else:
-                               raise RuntimeError("Parameter '%s' to function '%s' has size 0." % (self.name, self.context.name))
+               if self.depth:
+                       dim = 3
+                       d = self.depth
 
-                       return "(%s * %s)" % (a_prod, b_prod)
-               else:
-                       return str(s)
+               if self.extent:
+                       dim = 4
+                       e = self.extent
 
+               return [ dim, w, h, d, e ]
 
-class glParameterIterator:
-       """Class to iterate over a list of glParameters.
-       
-       Objects of this class are returned by the parameterIterator method of
-       the glFunction class.  They are used to iterate over the list of
-       parameters to the function."""
-
-       def __init__(self, data):
-               self.data = data
-               self.index = 0
-
-       def __iter__(self):
-               return self
-
-       def next(self):
-               if self.index == len( self.data ):
-                       raise StopIteration
-               i = self.index
-               self.index += 1
-               return self.data[i]
-
-
-class glFunction( glItem ):
-       real_name = ""
-       fn_alias = None
-       fn_offset = -1
-       fn_return_type = "void"
-       fn_parameters = []
-
-       def __init__(self, context, name, attrs):
-               self.fn_alias = attrs.get('alias', None)
-               self.fn_parameters = []
-               self.image = None
-               self.count_parameter_list = []
-
-               temp = attrs.get('offset', None)
-               if temp == None or temp == "?":
-                       self.fn_offset = -1
-               else:
-                       self.fn_offset = int(temp)
 
-               fn_name = attrs.get('name', None)
-               if self.fn_alias != None:
-                       self.real_name = self.fn_alias
-               else:
-                       self.real_name = fn_name
+       def get_stack_size(self):
+               return self.type_expr.get_stack_size()
 
-               glItem.__init__(self, name, fn_name, context)
-               return
 
+       def size(self):
+               if self.is_image():
+                       return 0
+               else:
+                       return self.type_expr.get_element_size()
 
-       def parameterIterator(self):
-               return glParameterIterator(self.fn_parameters)
 
+       def get_element_count(self):
+               c = self.type_expr.get_element_count()
+               if c == 0:
+                       return 1
 
-       def startElement(self, name, attrs):
-               if name == "param":
-                       try:
-                               self.context.factory.create(self, name, attrs)
-                       except RuntimeError:
-                               print "Error with parameter '%s' in function '%s'." \
-                                       % (attrs.get('name','(unknown)'), self.name)
-                               raise
-               elif name == "return":
-                       self.set_return_type(attrs.get('type', None))
+               return c
 
 
-       def append(self, tag_name, p):
-               if tag_name != "param":
-                       raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
+       def size_string(self, use_parens = 1):
+               s = self.size()
+               if self.counter or self.count_parameter_list:
+                       list = [ "compsize" ]
 
-               if p.width:
-                       self.image = p
+                       if self.counter and self.count_parameter_list:
+                               list.append( self.counter )
+                       elif self.counter:
+                               list = [ self.counter ]
 
-               self.fn_parameters.append(p)
-               if p.count_parameter_list != []:
-                       self.count_parameter_list.extend( p.count_parameter_list )
+                       if s > 1:
+                               list.append( str(s) )
 
+                       if len(list) > 1 and use_parens :
+                               return "(%s)" % (string.join(list, " * "))
+                       else:
+                               return string.join(list, " * ")
 
-       def set_return_type(self, t):
-               self.fn_return_type = t
+               elif self.is_image():
+                       return "compsize"
+               else:
+                       return str(s)
 
 
-       def get_parameter_string(self):
-               arg_string = ""
-               comma = ""
-               for p in glFunction.parameterIterator(self):
-                       arg_string = arg_string + comma + p.p_type_string + " " + p.name
-                       comma = ", "
-
-               if arg_string == "":
-                       arg_string = "void"
-
-               return arg_string
-
-
-class glItemFactory:
-       """Factory to create objects derived from glItem."""
-    
-       def create(self, context, name, attrs):
-               if name == "function":
-                       return glFunction(context, name, attrs)
-               elif name == "type":
-                       return glType(context, name, attrs)
-               elif name == "enum":
-                       return glEnum(context, name, attrs)
-               elif name == "param":
-                       return glParameter(context, name, attrs)
+       def format_string(self):
+               if self.type_expr.original_string == "GLenum":
+                       return "0x%x"
                else:
-                       return None
+                       return self.type_expr.format_string()
 
 
-class glFunctionIterator:
-       """Class to iterate over a list of glFunctions
 
-       Objects of this classare returned by
-       FilterGLAPISpecBase::functionIterator.  This default version
-       iterates over the functions in order of dispatch table offset.  All
-       of the "true" functions are iterated first, followed by the alias
-       functions."""
-
-       def __init__(self, context):
+class gl_function( gl_item ):
+       def __init__(self, element, context):
                self.context = context
-               self.keys = context.functions.keys()
-               self.keys.sort()
-
-               self.prevk = -1
-               self.direction = 1
+               self.name = None
 
-               for self.index in range(0, len(self.keys)):
-                       if self.keys[ self.index ] >= 0: break
+               self.entry_points = []
+               self.return_type = "void"
+               self.parameters = []
+               self.offset = -1
+               self.uninitialized = 1
+               self.images = []
 
-               if self.index == len(self.keys):
-                       self.direction = -1
-                       self.index -= 1
+               self.process_element( element )
 
-               self.split = self.index - 1
                return
 
+       
+       def process_element(self, element):
+               name = element.nsProp( "name", None )
+               alias = element.nsProp( "alias", None )
 
-       def __iter__(self):
-               return self
-
-
-       def next(self):
-               if self.index < 0:
-                       raise StopIteration
-
-               k = self.keys[ self.index ]
+               self.entry_points.append( name )
+               if alias:
+                       true_name = alias
+               else:
+                       true_name = name
+
+                       # Only try to set the offset when a non-alias
+                       # entry-point is being processes.
+
+                       offset = element.nsProp( "offset", None )
+                       if offset:
+                               try:
+                                       o = int( offset )
+                                       self.offset = o
+                               except Exception, e:
+                                       self.offset = -1
+
+
+               if not self.name:
+                       self.name = true_name
+               elif self.name != true_name:
+                       raise RuntimeError("Function true name redefined.  Was %s, now %s." % (self.name, true_name))
+
+
+               # There are two possible cases.  The first time an entry-point
+               # with data is seen, self.uninitialzied will be 1.  On that
+               # pass, we just fill in the data.  The next time an
+               # entry-point with data is seen, self.uninitialized will be 0.
+               # On that pass we have to make that the new values match the
+               # valuse from the previous entry-point.
+
+               child = element.children
+               if self.uninitialized:
+                       while child:
+                               if child.type == "element":
+                                       if child.name == "return":
+                                               self.return_type = child.nsProp( "type", None )
+                                       elif child.name == "param":
+                                               param = self.context.factory.create_item( "parameter", child, self.context)
+                                               self.parameters.append( param )
+
+                               child = child.next
+               else:
+                       parameters = []
+                       while child:
+                               if child.type == "element":
+                                       if child.name == "return":
+                                               return_type = child.nsProp( "type", None )
+                                               if self.return_type != return_type:
+                                                       raise RuntimeError( "Return type changed in %s.  Was %s, now %s." % (name, self.return_type, return_type))
+                                       elif child.name == "param":
+                                               param = self.context.factory.create_item( "parameter", child, self.context)
+                                               parameters.append( param )
+
+                               child = child.next
+
+                       if len(parameters) != len(self.parameters):
+                               raise RuntimeError( "Parameter count mismatch in %s.  Was %d, now %d." % (name, len(self.parameters), len(parameters)))
+
+                       for j in range(0, len(parameters)):
+                               p1 = parameters[j]
+                               p2 = self.parameters[j]
+                               if not p1.compatible( p2 ):
+                                       raise RuntimeError( 'Parameter type mismatch in %s.  "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string))
+
+
+                       # This is done becuase we may hit an alias before we
+                       # hit the "real" entry.  The aliases may not have all
+                       # of the parameter information (e.g., counter,
+                       # variable_param, etc. fields) required to generate
+                       # GLX code.
+
+                       if true_name == name:
+                               self.parameters = parameters
+
+                               for param in self.parameters:
+                                       if param.is_image():
+                                               self.images.append( param )
+
+               if true_name == name:
+                       for param in self.parameters:
+                               if param.is_image():
+                                       self.images.append( param )
+
+               if element.children:
+                       self.uninitialized = 0
 
-               #if self.context.functions[k].fn_alias == None:
-               #       if k != self.prevk + 1:
-               #               print 'Missing offset %d' % (prevk)
-               #       self.prevk = int(k)
+               return
 
-               self.index += self.direction
 
-               if self.index == len(self.keys):
-                       self.index = self.split
-                       self.direction = -1
+       def get_images(self):
+               """Return potentially empty list of input images."""
+               return self.images
 
-               return self.context.functions[k]
 
+       def parameterIterator(self):
+               return self.parameters.__iter__();
 
-class FilterGLAPISpecBase(saxutils.XMLFilterBase):
-       name = "a"
-       license = "The license for this file is unspecified."
-       functions = {}
-       next_alias = -2
-       types = {}
-       xref = {}
-       current_object = None
-       factory = None
-       current_category = ""
 
-       def __init__(self):
-               saxutils.XMLFilterBase.__init__(self)
-               self.functions = {}
-               self.types = {}
-               self.xref = {}
-               self.factory = glItemFactory()
-               self.header_tag = None
-               self.undef_list = []
+       def get_parameter_string(self):
+               list = []
+               for p in self.parameters:
+                       list.append( p.string() )
 
+               if len(list) == 0:
+                       return "void"
+               else:
+                       return string.join(list, ", ")
+
+
+class gl_item_factory:
+       """Factory to create objects derived from gl_item."""
+
+       def create_item(self, item_name, element, context):
+               if item_name == "function":
+                       return gl_function(element, context)
+               if item_name == "type":
+                       return gl_type(element, context)
+               elif item_name == "enum":
+                       return gl_enum(element, context)
+               elif item_name == "parameter":
+                       return gl_parameter(element, context)
+               elif item_name == "api":
+                       return gl_api(self)
+               else:
+                       return None
 
-       def find_type(self,type_name):
-               for t in self.types:
-                       if re.compile(t).search(type_name):
-                               return self.types[t]
-               print "Unable to find base type matching \"%s\"." % (type_name)
-               return None
 
+class gl_api:
+       def __init__(self, factory):
+               self.functions_by_name = {}
+               self.enums_by_name = {}
+               self.types_by_name = {}
+               self.category_dict = {}
 
-       def find_function(self,function_name):
-               index = self.xref[function_name]
-               return self.functions[index]
+               self.factory = factory
 
+               typeexpr.create_initial_types()
+               return
 
-       def functionIterator(self):
-               return glFunctionIterator(self)
 
+       def process_element(self, doc):
+               element = doc.children
+               while element.type != "element" or element.name != "OpenGLAPI":
+                       element = element.next
 
-       def printFunctions(self):
-               for f in self.functionIterator():
-                       self.printFunction(f)
+               if element:
+                       self.process_OpenGLAPI(element)
                return
 
 
-       def printHeader(self):
-               """Print the header associated with all files and call the printRealHeader method."""
+       def process_OpenGLAPI(self, element):
+               child = element.children
+               while child:
+                       if child.type == "element":
+                               if child.name == "category":
+                                       self.process_category( child )
+                               elif child.name == "OpenGLAPI":
+                                       self.process_OpenGLAPI( child )
 
-               print '/* DO NOT EDIT - This file generated automatically by %s script */' \
-                       % (self.name)
-               print ''
-               print '/*'
-               print ' * ' + self.license.replace('\n', '\n * ')
-               print ' */'
-               print ''
-               if self.header_tag:
-                   print '#if !defined( %s )' % (self.header_tag)
-                   print '#  define %s' % (self.header_tag)
-                   print ''
-               self.printRealHeader();
-               return
+                       child = child.next
 
+               return
 
-       def printFooter(self):
-               """Print the header associated with all files and call the printRealFooter method."""
 
-               self.printFunctions()
-               self.printRealFooter()
-               if self.header_tag:
-                       if self.undef_list:
-                               print ''
-                               for u in self.undef_list:
-                                       print "#  undef %s" % (u)
-                       print ''
-                       print '#endif /* !defined( %s ) */' % (self.header_tag)
+       def process_category(self, cat):
+               cat_name = cat.nsProp( "name", None )
+               cat_number = cat.nsProp( "number", None )
 
+               child = cat.children
+               while child:
+                       if child.type == "element":
+                               if child.name == "function":
+                                       func_name = real_function_name( child )
 
-       def get_category_define(self):
-               """Convert the category name to the #define that would be found in glext.h"""
-
-               if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
-                       s = self.current_category
-                       return "GL_VERSION_" + s.replace(".", "_")
-               else:
-                       return self.current_category
+                                       if self.functions_by_name.has_key( func_name ):
+                                               func = self.functions_by_name[ func_name ]
+                                               func.process_element( child )
+                                       else:
+                                               func = self.factory.create_item( "function", child, self )
+                                               self.functions_by_name[ func_name ] = func
 
+                                       if func_name == child.nsProp("name", None):
+                                               self.category_dict[ func.name ] = [cat_name, cat_number]
 
-       def append(self, object_type, obj):
-               if object_type == "function":
-                       # If the function is not an alias and has a negative
-                       # offset, then we do not need to track it.  These are
-                       # functions that don't have an assigned offset
+                               elif child.name == "enum":
+                                       enum = self.factory.create_item( "enum", child, self )
+                                       self.enums_by_name[ enum.name ] = enum
+                               elif child.name == "type":
+                                       t = self.factory.create_item( "type", child, self )
+                                       self.types_by_name[ "GL" + t.name ] = t
 
-                       if obj.fn_offset >= 0 or obj.fn_alias != None:
-                               if obj.fn_offset >= 0:
-                                       index = obj.fn_offset
-                               else:
-                                       index = self.next_alias
-                                       self.next_alias -= 1
 
-                               self.functions[index] = obj
-                               self.xref[obj.name] = index
-               elif object_type == "type":
-                       self.types[obj.name] = obj
+                       child = child.next
 
                return
 
 
-       def startElement(self, name, attrs):
-               """Start a new element in the XML stream.
-               
-               Starts a new element.  There are three types of elements that
-               are specially handled by this function.  When a "category"
-               element is encountered, the name of the category is saved.
-               If an element is encountered and no API object is
-               in-progress, a new object is created using the API factory.
-               Any future elements, until that API object is closed, are
-               passed to the current objects startElement method.
-       
-               This paradigm was chosen becuase it allows subclasses of the
-               basic API types (i.e., glFunction, glEnum, etc.) to handle
-               additional XML data, GLX protocol information,  that the base
-               classes do not know about."""
-
-               if self.current_object != None:
-                       self.current_object.startElement(name, attrs)
-               elif name == "category":
-                       self.current_category = attrs.get('name', "")
-               else:
-                       self.current_object = self.factory.create(self, name, attrs)
-               return
+       def functionIterateByOffset(self):
+               max_offset = -1
+               for func in self.functions_by_name.itervalues():
+                       if func.offset > max_offset:
+                               max_offset = func.offset
 
 
-       def endElement(self, name):
-               if self.current_object != None:
-                       if self.current_object.endElement(name):
-                               self.current_object = None
-               return
+               temp = [None for i in range(0, max_offset + 1)]
+               for func in self.functions_by_name.itervalues():
+                       if func.offset != -1:
+                               temp[ func.offset ] = func
 
 
-       def printPure(self):
-               self.undef_list.append("PURE")
-               print """#  if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
-#    define PURE __attribute__((pure))
-#  else
-#    define PURE
-#  endif"""
+               list = []
+               for i in range(0, max_offset + 1):
+                       if temp[i]:
+                               list.append(temp[i])
 
-       def printFastcall(self):
-               self.undef_list.append("FASTCALL")
-               print """#  if defined(__i386__) && defined(__GNUC__)
-#    define FASTCALL __attribute__((fastcall))
-#  else
-#    define FASTCALL
-#  endif"""
+               return list.__iter__();
 
-       def printVisibility(self, S, s):
-               self.undef_list.append(S)
-               print """#  if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
-#    define %s  __attribute__((visibility("%s")))
-#  else
-#    define %s
-#  endif""" % (S, s, S)
 
-       def printNoinline(self):
-               self.undef_list.append("NOINLINE")
-               print """#  if defined(__GNUC__)
-#    define NOINLINE __attribute__((noinline))
-#  else
-#    define NOINLINE
-#  endif"""
+       def functionIterateAll(self):
+               return self.functions_by_name.itervalues()
 
-       def printHaveAlias(self):
-               self.undef_list.append("HAVE_ALIAS")
-               print """#  if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
-#    define HAVE_ALIAS
-#  endif"""
 
-       def printFunction(self,offset):
-               """Print a single function.
+       def enumIterateByName(self):
+               keys = self.enums_by_name.keys()
+               keys.sort()
+               
+               list = []
+               for enum in keys:
+                       list.append( self.enums_by_name[ enum ] )
 
-               In the base class, this function is empty.  All derived
-               classes should over-ride this function."""
-               return
-    
+               return list.__iter__()
 
-       def printRealHeader(self):
-               """Print the "real" header for the created file.
 
-               In the base class, this function is empty.  All derived
-               classes should over-ride this function."""
-               return
+       def get_category_for_name( self, name ):
+               if self.category_dict.has_key(name):
+                       return self.category_dict[name]
+               else:
+                       return ["<unknown category>", None]
 
 
-       def printRealFooter(self):
-               """Print the "real" footer for the created file.
+       def typeIterate(self):
+               return self.types_by_name.itervalues()
 
-               In the base class, this function is empty.  All derived
-               classes should over-ride this function."""
-               return
+
+       def find_type( self, type_name ):
+               if type_name in self.types_by_name:
+                       return self.types_by_name[ type_name ].type_expr
+               else:
+                       print "Unable to find base type matching \"%s\"." % (type_name)
+                       return None