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