glapi: Read GLES information from XML.
[mesa.git] / src / mapi / glapi / gen / gl_XML.py
1 #!/usr/bin/env python
2
3 # (C) Copyright IBM Corporation 2004, 2005
4 # All Rights Reserved.
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the "Software"),
8 # to deal in the Software without restriction, including without limitation
9 # on the rights to use, copy, modify, merge, publish, distribute, sub
10 # license, and/or sell copies of the Software, and to permit persons to whom
11 # the Software is furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice (including the next
14 # paragraph) shall be included in all copies or substantial portions of the
15 # Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24 #
25 # Authors:
26 # Ian Romanick <idr@us.ibm.com>
27
28 from decimal import Decimal
29 import libxml2
30 import re, sys, string
31 import typeexpr
32
33
34 def parse_GL_API( file_name, factory = None ):
35 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 )
36 ret = doc.xincludeProcess()
37
38 if not factory:
39 factory = gl_item_factory()
40
41 api = factory.create_item( "api", None, None )
42 api.process_element( doc )
43
44 # After the XML has been processed, we need to go back and assign
45 # dispatch offsets to the functions that request that their offsets
46 # be assigned by the scripts. Typically this means all functions
47 # that are not part of the ABI.
48
49 for func in api.functionIterateByCategory():
50 if func.assign_offset:
51 func.offset = api.next_offset;
52 api.next_offset += 1
53
54 doc.freeDoc()
55
56 return api
57
58
59 def is_attr_true( element, name ):
60 """Read a name value from an element's attributes.
61
62 The value read from the attribute list must be either 'true' or
63 'false'. If the value is 'false', zero will be returned. If the
64 value is 'true', non-zero will be returned. An exception will be
65 raised for any other value."""
66
67 value = element.nsProp( name, None )
68 if value == "true":
69 return 1
70 elif value == "false":
71 return 0
72 else:
73 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
74
75
76 class gl_print_base(object):
77 """Base class of all API pretty-printers.
78
79 In the model-view-controller pattern, this is the view. Any derived
80 class will want to over-ride the printBody, printRealHader, and
81 printRealFooter methods. Some derived classes may want to over-ride
82 printHeader and printFooter, or even Print (though this is unlikely).
83 """
84
85 def __init__(self):
86 # Name of the script that is generating the output file.
87 # Every derived class should set this to the name of its
88 # source file.
89
90 self.name = "a"
91
92
93 # License on the *generated* source file. This may differ
94 # from the license on the script that is generating the file.
95 # Every derived class should set this to some reasonable
96 # value.
97 #
98 # See license.py for an example of a reasonable value.
99
100 self.license = "The license for this file is unspecified."
101
102
103 # The header_tag is the name of the C preprocessor define
104 # used to prevent multiple inclusion. Typically only
105 # generated C header files need this to be set. Setting it
106 # causes code to be generated automatically in printHeader
107 # and printFooter.
108
109 self.header_tag = None
110
111
112 # List of file-private defines that must be undefined at the
113 # end of the file. This can be used in header files to define
114 # names for use in the file, then undefine them at the end of
115 # the header file.
116
117 self.undef_list = []
118 return
119
120
121 def Print(self, api):
122 self.printHeader()
123 self.printBody(api)
124 self.printFooter()
125 return
126
127
128 def printHeader(self):
129 """Print the header associated with all files and call the printRealHeader method."""
130
131 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
132 % (self.name)
133 print ''
134 print '/*'
135 print ' * ' + self.license.replace('\n', '\n * ')
136 print ' */'
137 print ''
138 if self.header_tag:
139 print '#if !defined( %s )' % (self.header_tag)
140 print '# define %s' % (self.header_tag)
141 print ''
142 self.printRealHeader();
143 return
144
145
146 def printFooter(self):
147 """Print the header associated with all files and call the printRealFooter method."""
148
149 self.printRealFooter()
150
151 if self.undef_list:
152 print ''
153 for u in self.undef_list:
154 print "# undef %s" % (u)
155
156 if self.header_tag:
157 print ''
158 print '#endif /* !defined( %s ) */' % (self.header_tag)
159
160
161 def printRealHeader(self):
162 """Print the "real" header for the created file.
163
164 In the base class, this function is empty. All derived
165 classes should over-ride this function."""
166 return
167
168
169 def printRealFooter(self):
170 """Print the "real" footer for the created file.
171
172 In the base class, this function is empty. All derived
173 classes should over-ride this function."""
174 return
175
176
177 def printPure(self):
178 """Conditionally define `PURE' function attribute.
179
180 Conditionally defines a preprocessor macro `PURE' that wraps
181 GCC's `pure' function attribute. The conditional code can be
182 easilly adapted to other compilers that support a similar
183 feature.
184
185 The name is also added to the file's undef_list.
186 """
187 self.undef_list.append("PURE")
188 print """# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
189 # define PURE __attribute__((pure))
190 # else
191 # define PURE
192 # endif"""
193 return
194
195
196 def printFastcall(self):
197 """Conditionally define `FASTCALL' function attribute.
198
199 Conditionally defines a preprocessor macro `FASTCALL' that
200 wraps GCC's `fastcall' function attribute. The conditional
201 code can be easilly adapted to other compilers that support a
202 similar feature.
203
204 The name is also added to the file's undef_list.
205 """
206
207 self.undef_list.append("FASTCALL")
208 print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
209 # define FASTCALL __attribute__((fastcall))
210 # else
211 # define FASTCALL
212 # endif"""
213 return
214
215
216 def printVisibility(self, S, s):
217 """Conditionally define visibility function attribute.
218
219 Conditionally defines a preprocessor macro name S that wraps
220 GCC's visibility function attribute. The visibility used is
221 the parameter s. The conditional code can be easilly adapted
222 to other compilers that support a similar feature.
223
224 The name is also added to the file's undef_list.
225 """
226
227 self.undef_list.append(S)
228 print """# if (defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) && defined(__ELF__))
229 # define %s __attribute__((visibility("%s")))
230 # else
231 # define %s
232 # endif""" % (S, s, S)
233 return
234
235
236 def printNoinline(self):
237 """Conditionally define `NOINLINE' function attribute.
238
239 Conditionally defines a preprocessor macro `NOINLINE' that
240 wraps GCC's `noinline' function attribute. The conditional
241 code can be easilly adapted to other compilers that support a
242 similar feature.
243
244 The name is also added to the file's undef_list.
245 """
246
247 self.undef_list.append("NOINLINE")
248 print """# if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590))
249 # define NOINLINE __attribute__((noinline))
250 # else
251 # define NOINLINE
252 # endif"""
253 return
254
255
256 def real_function_name(element):
257 name = element.nsProp( "name", None )
258 alias = element.nsProp( "alias", None )
259
260 if alias:
261 return alias
262 else:
263 return name
264
265
266 def real_category_name(c):
267 if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
268 return "GL_VERSION_" + c.replace(".", "_")
269 else:
270 return c
271
272
273 def classify_category(name, number):
274 """Based on the category name and number, select a numerical class for it.
275
276 Categories are divided into four classes numbered 0 through 3. The
277 classes are:
278
279 0. Core GL versions, sorted by version number.
280 1. ARB extensions, sorted by extension number.
281 2. Non-ARB extensions, sorted by extension number.
282 3. Un-numbered extensions, sorted by extension name.
283 """
284
285 try:
286 core_version = float(name)
287 except Exception,e:
288 core_version = 0.0
289
290 if core_version > 0.0:
291 cat_type = 0
292 key = name
293 elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"):
294 cat_type = 1
295 key = int(number)
296 else:
297 if number != None:
298 cat_type = 2
299 key = int(number)
300 else:
301 cat_type = 3
302 key = name
303
304
305 return [cat_type, key]
306
307
308 def create_parameter_string(parameters, include_names):
309 """Create a parameter string from a list of gl_parameters."""
310
311 list = []
312 for p in parameters:
313 if p.is_padding:
314 continue
315
316 if include_names:
317 list.append( p.string() )
318 else:
319 list.append( p.type_string() )
320
321 if len(list) == 0: list = ["void"]
322
323 return string.join(list, ", ")
324
325
326 class gl_item(object):
327 def __init__(self, element, context):
328 self.context = context
329 self.name = element.nsProp( "name", None )
330 self.category = real_category_name( element.parent.nsProp( "name", None ) )
331 return
332
333
334 class gl_type( gl_item ):
335 def __init__(self, element, context):
336 gl_item.__init__(self, element, context)
337 self.size = int( element.nsProp( "size", None ), 0 )
338
339 te = typeexpr.type_expression( None )
340 tn = typeexpr.type_node()
341 tn.size = int( element.nsProp( "size", None ), 0 )
342 tn.integer = not is_attr_true( element, "float" )
343 tn.unsigned = is_attr_true( element, "unsigned" )
344 tn.pointer = is_attr_true( element, "pointer" )
345 tn.name = "GL" + self.name
346 te.set_base_type_node( tn )
347
348 self.type_expr = te
349 return
350
351
352 def get_type_expression(self):
353 return self.type_expr
354
355
356 class gl_enum( gl_item ):
357 def __init__(self, element, context):
358 gl_item.__init__(self, element, context)
359 self.value = int( element.nsProp( "value", None ), 0 )
360
361 temp = element.nsProp( "count", None )
362 if not temp or temp == "?":
363 self.default_count = -1
364 else:
365 try:
366 c = int(temp)
367 except Exception,e:
368 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
369
370 self.default_count = c
371
372 return
373
374
375 def priority(self):
376 """Calculate a 'priority' for this enum name.
377
378 When an enum is looked up by number, there may be many
379 possible names, but only one is the 'prefered' name. The
380 priority is used to select which name is the 'best'.
381
382 Highest precedence is given to core GL name. ARB extension
383 names have the next highest, followed by EXT extension names.
384 Vendor extension names are the lowest.
385 """
386
387 if self.name.endswith( "_BIT" ):
388 bias = 1
389 else:
390 bias = 0
391
392 if self.category.startswith( "GL_VERSION_" ):
393 priority = 0
394 elif self.category.startswith( "GL_ARB_" ):
395 priority = 2
396 elif self.category.startswith( "GL_EXT_" ):
397 priority = 4
398 else:
399 priority = 6
400
401 return priority + bias
402
403
404
405 class gl_parameter(object):
406 def __init__(self, element, context):
407 self.name = element.nsProp( "name", None )
408
409 ts = element.nsProp( "type", None )
410 self.type_expr = typeexpr.type_expression( ts, context )
411
412 temp = element.nsProp( "variable_param", None )
413 if temp:
414 self.count_parameter_list = temp.split( ' ' )
415 else:
416 self.count_parameter_list = []
417
418 # The count tag can be either a numeric string or the name of
419 # a variable. If it is the name of a variable, the int(c)
420 # statement will throw an exception, and the except block will
421 # take over.
422
423 c = element.nsProp( "count", None )
424 try:
425 count = int(c)
426 self.count = count
427 self.counter = None
428 except Exception,e:
429 count = 1
430 self.count = 0
431 self.counter = c
432
433 self.count_scale = int(element.nsProp( "count_scale", None ))
434
435 elements = (count * self.count_scale)
436 if elements == 1:
437 elements = 0
438
439 #if ts == "GLdouble":
440 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
441 # print '/* # elements = %u */' % (elements)
442 self.type_expr.set_elements( elements )
443 #if ts == "GLdouble":
444 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
445
446 self.is_client_only = is_attr_true( element, 'client_only' )
447 self.is_counter = is_attr_true( element, 'counter' )
448 self.is_output = is_attr_true( element, 'output' )
449
450
451 # Pixel data has special parameters.
452
453 self.width = element.nsProp('img_width', None)
454 self.height = element.nsProp('img_height', None)
455 self.depth = element.nsProp('img_depth', None)
456 self.extent = element.nsProp('img_extent', None)
457
458 self.img_xoff = element.nsProp('img_xoff', None)
459 self.img_yoff = element.nsProp('img_yoff', None)
460 self.img_zoff = element.nsProp('img_zoff', None)
461 self.img_woff = element.nsProp('img_woff', None)
462
463 self.img_format = element.nsProp('img_format', None)
464 self.img_type = element.nsProp('img_type', None)
465 self.img_target = element.nsProp('img_target', None)
466
467 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
468 self.img_null_flag = is_attr_true( element, 'img_null_flag' )
469 self.img_send_null = is_attr_true( element, 'img_send_null' )
470
471 self.is_padding = is_attr_true( element, 'padding' )
472 return
473
474
475 def compatible(self, other):
476 return 1
477
478
479 def is_array(self):
480 return self.is_pointer()
481
482
483 def is_pointer(self):
484 return self.type_expr.is_pointer()
485
486
487 def is_image(self):
488 if self.width:
489 return 1
490 else:
491 return 0
492
493
494 def is_variable_length(self):
495 return len(self.count_parameter_list) or self.counter
496
497
498 def is_64_bit(self):
499 count = self.type_expr.get_element_count()
500 if count:
501 if (self.size() / count) == 8:
502 return 1
503 else:
504 if self.size() == 8:
505 return 1
506
507 return 0
508
509
510 def string(self):
511 return self.type_expr.original_string + " " + self.name
512
513
514 def type_string(self):
515 return self.type_expr.original_string
516
517
518 def get_base_type_string(self):
519 return self.type_expr.get_base_name()
520
521
522 def get_dimensions(self):
523 if not self.width:
524 return [ 0, "0", "0", "0", "0" ]
525
526 dim = 1
527 w = self.width
528 h = "1"
529 d = "1"
530 e = "1"
531
532 if self.height:
533 dim = 2
534 h = self.height
535
536 if self.depth:
537 dim = 3
538 d = self.depth
539
540 if self.extent:
541 dim = 4
542 e = self.extent
543
544 return [ dim, w, h, d, e ]
545
546
547 def get_stack_size(self):
548 return self.type_expr.get_stack_size()
549
550
551 def size(self):
552 if self.is_image():
553 return 0
554 else:
555 return self.type_expr.get_element_size()
556
557
558 def get_element_count(self):
559 c = self.type_expr.get_element_count()
560 if c == 0:
561 return 1
562
563 return c
564
565
566 def size_string(self, use_parens = 1):
567 s = self.size()
568 if self.counter or self.count_parameter_list:
569 list = [ "compsize" ]
570
571 if self.counter and self.count_parameter_list:
572 list.append( self.counter )
573 elif self.counter:
574 list = [ self.counter ]
575
576 if s > 1:
577 list.append( str(s) )
578
579 if len(list) > 1 and use_parens :
580 return "(%s)" % (string.join(list, " * "))
581 else:
582 return string.join(list, " * ")
583
584 elif self.is_image():
585 return "compsize"
586 else:
587 return str(s)
588
589
590 def format_string(self):
591 if self.type_expr.original_string == "GLenum":
592 return "0x%x"
593 else:
594 return self.type_expr.format_string()
595
596
597
598 class gl_function( gl_item ):
599 def __init__(self, element, context):
600 self.context = context
601 self.name = None
602
603 self.entry_points = []
604 self.return_type = "void"
605 self.parameters = []
606 self.offset = -1
607 self.initialized = 0
608 self.images = []
609
610 # self.entry_point_api_map[name][api] is a decimal value
611 # indicating the earliest version of the given API in which
612 # each entry point exists. Every entry point is included in
613 # the first level of the map; the second level of the map only
614 # lists APIs which contain the entry point in at least one
615 # version. For example,
616 # self.entry_point_gles_map['ClipPlanex'] == { 'es1':
617 # Decimal('1.1') }.
618 self.entry_point_api_map = {}
619
620 self.assign_offset = 0
621
622 self.static_entry_points = []
623
624 # Track the parameter string (for the function prototype)
625 # for each entry-point. This is done because some functions
626 # change their prototype slightly when promoted from extension
627 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
628 # are good examples of this. Scripts that need to generate
629 # code for these differing aliases need to real prototype
630 # for each entry-point. Otherwise, they may generate code
631 # that won't compile.
632
633 self.entry_point_parameters = {}
634
635 self.process_element( element )
636
637 return
638
639
640 def process_element(self, element):
641 name = element.nsProp( "name", None )
642 alias = element.nsProp( "alias", None )
643
644 if is_attr_true(element, "static_dispatch"):
645 self.static_entry_points.append(name)
646
647 self.entry_points.append( name )
648
649 self.entry_point_api_map[name] = {}
650 for api in ('es1', 'es2'):
651 version_str = element.nsProp(api, None)
652 assert version_str is not None
653 if version_str != 'none':
654 self.entry_point_api_map[name][api] = Decimal(version_str)
655
656 if alias:
657 true_name = alias
658 else:
659 true_name = name
660
661 # Only try to set the offset when a non-alias
662 # entry-point is being processes.
663
664 offset = element.nsProp( "offset", None )
665 if offset:
666 try:
667 o = int( offset )
668 self.offset = o
669 except Exception, e:
670 self.offset = -1
671 if offset == "assign":
672 self.assign_offset = 1
673
674
675 if not self.name:
676 self.name = true_name
677 elif self.name != true_name:
678 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
679
680
681 # There are two possible cases. The first time an entry-point
682 # with data is seen, self.initialized will be 0. On that
683 # pass, we just fill in the data. The next time an
684 # entry-point with data is seen, self.initialized will be 1.
685 # On that pass we have to make that the new values match the
686 # valuse from the previous entry-point.
687
688 parameters = []
689 return_type = "void"
690 child = element.children
691 while child:
692 if child.type == "element":
693 if child.name == "return":
694 return_type = child.nsProp( "type", None )
695 elif child.name == "param":
696 param = self.context.factory.create_item( "parameter", child, self.context)
697 parameters.append( param )
698
699 child = child.next
700
701
702 if self.initialized:
703 if self.return_type != return_type:
704 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
705
706 if len(parameters) != len(self.parameters):
707 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
708
709 for j in range(0, len(parameters)):
710 p1 = parameters[j]
711 p2 = self.parameters[j]
712 if not p1.compatible( p2 ):
713 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))
714
715
716 if true_name == name or not self.initialized:
717 self.return_type = return_type
718 self.parameters = parameters
719
720 for param in self.parameters:
721 if param.is_image():
722 self.images.append( param )
723
724 if element.children:
725 self.initialized = 1
726 self.entry_point_parameters[name] = parameters
727 else:
728 self.entry_point_parameters[name] = []
729
730 return
731
732 def filter_entry_points(self, entry_point_list):
733 """Filter out entry points not in entry_point_list."""
734 if not self.initialized:
735 raise RuntimeError('%s is not initialized yet' % self.name)
736
737 entry_points = []
738 for ent in self.entry_points:
739 if ent not in entry_point_list:
740 if ent in self.static_entry_points:
741 self.static_entry_points.remove(ent)
742 self.entry_point_parameters.pop(ent)
743 else:
744 entry_points.append(ent)
745
746 if not entry_points:
747 raise RuntimeError('%s has no entry point after filtering' % self.name)
748
749 self.entry_points = entry_points
750 if self.name not in entry_points:
751 # use the first remaining entry point
752 self.name = entry_points[0]
753 self.parameters = self.entry_point_parameters[entry_points[0]]
754
755 def get_images(self):
756 """Return potentially empty list of input images."""
757 return self.images
758
759
760 def parameterIterator(self):
761 return self.parameters.__iter__();
762
763
764 def get_parameter_string(self, entrypoint = None):
765 if entrypoint:
766 params = self.entry_point_parameters[ entrypoint ]
767 else:
768 params = self.parameters
769
770 return create_parameter_string( params, 1 )
771
772 def get_called_parameter_string(self):
773 p_string = ""
774 comma = ""
775
776 for p in self.parameterIterator():
777 p_string = p_string + comma + p.name
778 comma = ", "
779
780 return p_string
781
782
783 def is_abi(self):
784 return (self.offset >= 0 and not self.assign_offset)
785
786 def is_static_entry_point(self, name):
787 return name in self.static_entry_points
788
789 def dispatch_name(self):
790 if self.name in self.static_entry_points:
791 return self.name
792 else:
793 return "_dispatch_stub_%u" % (self.offset)
794
795 def static_name(self, name):
796 if name in self.static_entry_points:
797 return name
798 else:
799 return "_dispatch_stub_%u" % (self.offset)
800
801 def entry_points_for_api_version(self, api, version = None):
802 """Return a list of the entry point names for this function
803 which are supported in the given API (and optionally, version).
804
805 Use the decimal.Decimal type to precisely express non-integer
806 versions.
807 """
808 result = []
809 for entry_point, api_to_ver in self.entry_point_api_map.iteritems():
810 if api not in api_to_ver:
811 continue
812 if version is not None and version < api_to_ver[api]:
813 continue
814 result.append(entry_point)
815 return result
816
817
818 class gl_item_factory(object):
819 """Factory to create objects derived from gl_item."""
820
821 def create_item(self, item_name, element, context):
822 if item_name == "function":
823 return gl_function(element, context)
824 if item_name == "type":
825 return gl_type(element, context)
826 elif item_name == "enum":
827 return gl_enum(element, context)
828 elif item_name == "parameter":
829 return gl_parameter(element, context)
830 elif item_name == "api":
831 return gl_api(self)
832 else:
833 return None
834
835
836 class gl_api(object):
837 def __init__(self, factory):
838 self.functions_by_name = {}
839 self.enums_by_name = {}
840 self.types_by_name = {}
841
842 self.category_dict = {}
843 self.categories = [{}, {}, {}, {}]
844
845 self.factory = factory
846
847 self.next_offset = 0
848
849 typeexpr.create_initial_types()
850 return
851
852 def filter_functions(self, entry_point_list):
853 """Filter out entry points not in entry_point_list."""
854 functions_by_name = {}
855 for func in self.functions_by_name.itervalues():
856 entry_points = [ent for ent in func.entry_points if ent in entry_point_list]
857 if entry_points:
858 func.filter_entry_points(entry_points)
859 functions_by_name[func.name] = func
860
861 self.functions_by_name = functions_by_name
862
863 def filter_functions_by_api(self, api, version = None):
864 """Filter out entry points not in the given API (or
865 optionally, not in the given version of the given API).
866 """
867 functions_by_name = {}
868 for func in self.functions_by_name.itervalues():
869 entry_points = func.entry_points_for_api_version(api, version)
870 if entry_points:
871 func.filter_entry_points(entry_points)
872 functions_by_name[func.name] = func
873
874 self.functions_by_name = functions_by_name
875
876 def process_element(self, doc):
877 element = doc.children
878 while element.type != "element" or element.name != "OpenGLAPI":
879 element = element.next
880
881 if element:
882 self.process_OpenGLAPI(element)
883 return
884
885
886 def process_OpenGLAPI(self, element):
887 child = element.children
888 while child:
889 if child.type == "element":
890 if child.name == "category":
891 self.process_category( child )
892 elif child.name == "OpenGLAPI":
893 self.process_OpenGLAPI( child )
894
895 child = child.next
896
897 return
898
899
900 def process_category(self, cat):
901 cat_name = cat.nsProp( "name", None )
902 cat_number = cat.nsProp( "number", None )
903
904 [cat_type, key] = classify_category(cat_name, cat_number)
905 self.categories[cat_type][key] = [cat_name, cat_number]
906
907 child = cat.children
908 while child:
909 if child.type == "element":
910 if child.name == "function":
911 func_name = real_function_name( child )
912
913 temp_name = child.nsProp( "name", None )
914 self.category_dict[ temp_name ] = [cat_name, cat_number]
915
916 if self.functions_by_name.has_key( func_name ):
917 func = self.functions_by_name[ func_name ]
918 func.process_element( child )
919 else:
920 func = self.factory.create_item( "function", child, self )
921 self.functions_by_name[ func_name ] = func
922
923 if func.offset >= self.next_offset:
924 self.next_offset = func.offset + 1
925
926
927 elif child.name == "enum":
928 enum = self.factory.create_item( "enum", child, self )
929 self.enums_by_name[ enum.name ] = enum
930 elif child.name == "type":
931 t = self.factory.create_item( "type", child, self )
932 self.types_by_name[ "GL" + t.name ] = t
933
934
935 child = child.next
936
937 return
938
939
940 def functionIterateByCategory(self, cat = None):
941 """Iterate over functions by category.
942
943 If cat is None, all known functions are iterated in category
944 order. See classify_category for details of the ordering.
945 Within a category, functions are sorted by name. If cat is
946 not None, then only functions in that category are iterated.
947 """
948 lists = [{}, {}, {}, {}]
949
950 for func in self.functionIterateAll():
951 [cat_name, cat_number] = self.category_dict[func.name]
952
953 if (cat == None) or (cat == cat_name):
954 [func_cat_type, key] = classify_category(cat_name, cat_number)
955
956 if not lists[func_cat_type].has_key(key):
957 lists[func_cat_type][key] = {}
958
959 lists[func_cat_type][key][func.name] = func
960
961
962 functions = []
963 for func_cat_type in range(0,4):
964 keys = lists[func_cat_type].keys()
965 keys.sort()
966
967 for key in keys:
968 names = lists[func_cat_type][key].keys()
969 names.sort()
970
971 for name in names:
972 functions.append(lists[func_cat_type][key][name])
973
974 return functions.__iter__()
975
976
977 def functionIterateByOffset(self):
978 max_offset = -1
979 for func in self.functions_by_name.itervalues():
980 if func.offset > max_offset:
981 max_offset = func.offset
982
983
984 temp = [None for i in range(0, max_offset + 1)]
985 for func in self.functions_by_name.itervalues():
986 if func.offset != -1:
987 temp[ func.offset ] = func
988
989
990 list = []
991 for i in range(0, max_offset + 1):
992 if temp[i]:
993 list.append(temp[i])
994
995 return list.__iter__();
996
997
998 def functionIterateAll(self):
999 return self.functions_by_name.itervalues()
1000
1001
1002 def enumIterateByName(self):
1003 keys = self.enums_by_name.keys()
1004 keys.sort()
1005
1006 list = []
1007 for enum in keys:
1008 list.append( self.enums_by_name[ enum ] )
1009
1010 return list.__iter__()
1011
1012
1013 def categoryIterate(self):
1014 """Iterate over categories.
1015
1016 Iterate over all known categories in the order specified by
1017 classify_category. Each iterated value is a tuple of the
1018 name and number (which may be None) of the category.
1019 """
1020
1021 list = []
1022 for cat_type in range(0,4):
1023 keys = self.categories[cat_type].keys()
1024 keys.sort()
1025
1026 for key in keys:
1027 list.append(self.categories[cat_type][key])
1028
1029 return list.__iter__()
1030
1031
1032 def get_category_for_name( self, name ):
1033 if self.category_dict.has_key(name):
1034 return self.category_dict[name]
1035 else:
1036 return ["<unknown category>", None]
1037
1038
1039 def typeIterate(self):
1040 return self.types_by_name.itervalues()
1041
1042
1043 def find_type( self, type_name ):
1044 if type_name in self.types_by_name:
1045 return self.types_by_name[ type_name ].type_expr
1046 else:
1047 print "Unable to find base type matching \"%s\"." % (type_name)
1048 return None