blob: bafb00306f8c8da9672e998054082c7cfd150036 [file] [log] [blame]
Ian Romanick66a55482005-06-21 23:42:43 +00001#!/usr/bin/env python
Ian Romanick73f59b02004-05-18 18:33:40 +00002
Ian Romanick5f1f2292005-01-07 02:39:09 +00003# (C) Copyright IBM Corporation 2004, 2005
Ian Romanick73f59b02004-05-18 18:33:40 +00004# 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
Ian Romanick66a55482005-06-21 23:42:43 +000028import libxml2
29import re, sys, string
30import typeexpr
Ian Romanick73f59b02004-05-18 18:33:40 +000031
Ian Romanick73f59b02004-05-18 18:33:40 +000032
Ian Romanick66a55482005-06-21 23:42:43 +000033def parse_GL_API( file_name, factory = None ):
34 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 )
35 ret = doc.xincludeProcess()
36
37 if not factory:
38 factory = gl_item_factory()
39
40 api = factory.create_item( "api", None, None )
41 api.process_element( doc )
42
Ian Romanickbf83e652006-08-24 20:14:45 +000043 # After the XML has been processed, we need to go back and assign
44 # dispatch offsets to the functions that request that their offsets
45 # be assigned by the scripts. Typically this means all functions
46 # that are not part of the ABI.
Ian Romanickbf83e652006-08-24 20:14:45 +000047
Ian Romanickeaeaaf62006-10-04 20:45:59 +000048 for func in api.functionIterateByCategory():
Ian Romanickbf83e652006-08-24 20:14:45 +000049 if func.assign_offset:
Ian Romanickeaeaaf62006-10-04 20:45:59 +000050 func.offset = api.next_offset;
51 api.next_offset += 1
Ian Romanickbf83e652006-08-24 20:14:45 +000052
Ian Romanick66a55482005-06-21 23:42:43 +000053 doc.freeDoc()
54
55 return api
56
57
58def is_attr_true( element, name ):
Ian Romanick73b4c1b2005-04-14 23:00:34 +000059 """Read a name value from an element's attributes.
60
61 The value read from the attribute list must be either 'true' or
62 'false'. If the value is 'false', zero will be returned. If the
63 value is 'true', non-zero will be returned. An exception will be
64 raised for any other value."""
65
Ian Romanick66a55482005-06-21 23:42:43 +000066 value = element.nsProp( name, None )
Ian Romanick73b4c1b2005-04-14 23:00:34 +000067 if value == "true":
68 return 1
69 elif value == "false":
70 return 0
71 else:
72 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
73
74
Ian Romanick66a55482005-06-21 23:42:43 +000075class gl_print_base:
76 """Base class of all API pretty-printers.
Ian Romanick93d2d542005-04-18 19:42:23 +000077
Ian Romanick66a55482005-06-21 23:42:43 +000078 In the model-view-controller pattern, this is the view. Any derived
79 class will want to over-ride the printBody, printRealHader, and
80 printRealFooter methods. Some derived classes may want to over-ride
81 printHeader and printFooter, or even Print (though this is unlikely).
Ian Romanick93d2d542005-04-18 19:42:23 +000082 """
Ian Romanickd03ab102005-04-18 21:30:20 +000083
Ian Romanick73f59b02004-05-18 18:33:40 +000084 def __init__(self):
Ian Romanick66a55482005-06-21 23:42:43 +000085 # Name of the script that is generating the output file.
86 # Every derived class should set this to the name of its
87 # source file.
88
89 self.name = "a"
90
91
92 # License on the *generated* source file. This may differ
93 # from the license on the script that is generating the file.
94 # Every derived class should set this to some reasonable
95 # value.
96 #
97 # See license.py for an example of a reasonable value.
98
99 self.license = "The license for this file is unspecified."
100
101
102 # The header_tag is the name of the C preprocessor define
103 # used to prevent multiple inclusion. Typically only
104 # generated C header files need this to be set. Setting it
105 # causes code to be generated automatically in printHeader
106 # and printFooter.
107
Ian Romanick16c3c742005-01-28 19:00:54 +0000108 self.header_tag = None
Ian Romanick66a55482005-06-21 23:42:43 +0000109
110
111 # List of file-private defines that must be undefined at the
112 # end of the file. This can be used in header files to define
113 # names for use in the file, then undefine them at the end of
114 # the header file.
115
Ian Romanickc2803582005-02-01 00:28:47 +0000116 self.undef_list = []
Ian Romanick66a55482005-06-21 23:42:43 +0000117 return
Ian Romanick73f59b02004-05-18 18:33:40 +0000118
Ian Romanicka9d033c2004-05-19 23:33:08 +0000119
Ian Romanick66a55482005-06-21 23:42:43 +0000120 def Print(self, api):
121 self.printHeader()
122 self.printBody(api)
123 self.printFooter()
Ian Romanick73f59b02004-05-18 18:33:40 +0000124 return
125
Ian Romanicka9d033c2004-05-19 23:33:08 +0000126
Ian Romanick73f59b02004-05-18 18:33:40 +0000127 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000128 """Print the header associated with all files and call the printRealHeader method."""
129
Ian Romanick73f59b02004-05-18 18:33:40 +0000130 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
131 % (self.name)
132 print ''
133 print '/*'
134 print ' * ' + self.license.replace('\n', '\n * ')
135 print ' */'
136 print ''
Ian Romanick16c3c742005-01-28 19:00:54 +0000137 if self.header_tag:
138 print '#if !defined( %s )' % (self.header_tag)
139 print '# define %s' % (self.header_tag)
140 print ''
Ian Romanick73f59b02004-05-18 18:33:40 +0000141 self.printRealHeader();
142 return
143
Ian Romanicka9d033c2004-05-19 23:33:08 +0000144
Ian Romanick73f59b02004-05-18 18:33:40 +0000145 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000146 """Print the header associated with all files and call the printRealFooter method."""
147
Ian Romanick73f59b02004-05-18 18:33:40 +0000148 self.printRealFooter()
Ian Romanick66a55482005-06-21 23:42:43 +0000149
150 if self.undef_list:
151 print ''
152 for u in self.undef_list:
153 print "# undef %s" % (u)
154
Ian Romanick16c3c742005-01-28 19:00:54 +0000155 if self.header_tag:
Ian Romanickc2803582005-02-01 00:28:47 +0000156 print ''
157 print '#endif /* !defined( %s ) */' % (self.header_tag)
Ian Romanick73f59b02004-05-18 18:33:40 +0000158
159
Ian Romanick73f59b02004-05-18 18:33:40 +0000160 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000161 """Print the "real" header for the created file.
162
163 In the base class, this function is empty. All derived
164 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000165 return
166
Ian Romanicka9d033c2004-05-19 23:33:08 +0000167
Ian Romanick73f59b02004-05-18 18:33:40 +0000168 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000169 """Print the "real" footer for the created file.
170
171 In the base class, this function is empty. All derived
172 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000173 return
Ian Romanick66a55482005-06-21 23:42:43 +0000174
175
176 def printPure(self):
177 """Conditionally define `PURE' function attribute.
178
179 Conditionally defines a preprocessor macro `PURE' that wraps
180 GCC's `pure' function attribute. The conditional code can be
181 easilly adapted to other compilers that support a similar
182 feature.
183
184 The name is also added to the file's undef_list.
185 """
186 self.undef_list.append("PURE")
187 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
188# define PURE __attribute__((pure))
189# else
190# define PURE
191# endif"""
192 return
193
194
195 def printFastcall(self):
196 """Conditionally define `FASTCALL' function attribute.
197
198 Conditionally defines a preprocessor macro `FASTCALL' that
199 wraps GCC's `fastcall' function attribute. The conditional
200 code can be easilly adapted to other compilers that support a
201 similar feature.
202
203 The name is also added to the file's undef_list.
204 """
205
206 self.undef_list.append("FASTCALL")
Brian Paulf468dfd2005-10-20 22:51:50 +0000207 print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
208# define FASTCALL __attribute__((fastcall))
209# else
210# define FASTCALL
211# endif"""
Ian Romanick66a55482005-06-21 23:42:43 +0000212 return
213
214
215 def printVisibility(self, S, s):
216 """Conditionally define visibility function attribute.
217
218 Conditionally defines a preprocessor macro name S that wraps
219 GCC's visibility function attribute. The visibility used is
220 the parameter s. The conditional code can be easilly adapted
221 to other compilers that support a similar feature.
222
223 The name is also added to the file's undef_list.
224 """
225
226 self.undef_list.append(S)
Adam Jacksonca1ac982005-08-26 17:50:39 +0000227 print """# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
Ian Romanick66a55482005-06-21 23:42:43 +0000228# define %s __attribute__((visibility("%s")))
229# else
230# define %s
231# endif""" % (S, s, S)
232 return
233
234
235 def printNoinline(self):
236 """Conditionally define `NOINLINE' function attribute.
237
238 Conditionally defines a preprocessor macro `NOINLINE' that
239 wraps GCC's `noinline' function attribute. The conditional
240 code can be easilly adapted to other compilers that support a
241 similar feature.
242
243 The name is also added to the file's undef_list.
244 """
245
246 self.undef_list.append("NOINLINE")
247 print """# if defined(__GNUC__)
248# define NOINLINE __attribute__((noinline))
249# else
250# define NOINLINE
251# endif"""
252 return
253
254
Ian Romanick66a55482005-06-21 23:42:43 +0000255def real_function_name(element):
256 name = element.nsProp( "name", None )
257 alias = element.nsProp( "alias", None )
258
259 if alias:
260 return alias
261 else:
262 return name
263
264
Ian Romanick5aafea02005-06-24 18:35:31 +0000265def real_category_name(c):
266 if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
267 return "GL_VERSION_" + c.replace(".", "_")
268 else:
269 return c
270
271
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000272def classify_category(name, number):
273 """Based on the category name and number, select a numerical class for it.
274
275 Categories are divided into four classes numbered 0 through 3. The
276 classes are:
277
278 0. Core GL versions, sorted by version number.
279 1. ARB extensions, sorted by extension number.
280 2. Non-ARB extensions, sorted by extension number.
281 3. Un-numbered extensions, sorted by extension name.
282 """
283
284 try:
285 core_version = float(name)
286 except Exception,e:
287 core_version = 0.0
288
289 if core_version > 0.0:
290 cat_type = 0
291 key = name
292 elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"):
293 cat_type = 1
294 key = int(number)
295 else:
296 if number != None:
297 cat_type = 2
298 key = int(number)
299 else:
300 cat_type = 3
301 key = name
302
303
304 return [cat_type, key]
305
306
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000307def create_parameter_string(parameters, include_names):
Ian Romanick5aafea02005-06-24 18:35:31 +0000308 """Create a parameter string from a list of gl_parameters."""
309
310 list = []
311 for p in parameters:
Ian Romanick0f733022008-12-09 14:43:09 -0800312 if p.is_padding:
313 continue
314
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000315 if include_names:
316 list.append( p.string() )
317 else:
318 list.append( p.type_string() )
Ian Romanick5aafea02005-06-24 18:35:31 +0000319
320 if len(list) == 0: list = ["void"]
321
322 return string.join(list, ", ")
323
324
Ian Romanick66a55482005-06-21 23:42:43 +0000325class gl_item:
326 def __init__(self, element, context):
327 self.context = context
Ian Romanick66a55482005-06-21 23:42:43 +0000328 self.name = element.nsProp( "name", None )
Ian Romanick5aafea02005-06-24 18:35:31 +0000329 self.category = real_category_name( element.parent.nsProp( "name", None ) )
Ian Romanick66a55482005-06-21 23:42:43 +0000330 return
331
332
333class gl_type( gl_item ):
334 def __init__(self, element, context):
335 gl_item.__init__(self, element, context)
336 self.size = int( element.nsProp( "size", None ), 0 )
337
338 te = typeexpr.type_expression( None )
339 tn = typeexpr.type_node()
340 tn.size = int( element.nsProp( "size", None ), 0 )
341 tn.integer = not is_attr_true( element, "float" )
342 tn.unsigned = is_attr_true( element, "unsigned" )
343 tn.name = "GL" + self.name
344 te.set_base_type_node( tn )
345
346 self.type_expr = te
347 return
348
349
350 def get_type_expression(self):
351 return self.type_expr
352
353
354class gl_enum( gl_item ):
355 def __init__(self, element, context):
356 gl_item.__init__(self, element, context)
357 self.value = int( element.nsProp( "value", None ), 0 )
358
359 temp = element.nsProp( "count", None )
360 if not temp or temp == "?":
361 self.default_count = -1
362 else:
363 try:
364 c = int(temp)
365 except Exception,e:
366 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
367
368 self.default_count = c
369
370 return
371
372
373 def priority(self):
374 """Calculate a 'priority' for this enum name.
375
376 When an enum is looked up by number, there may be many
377 possible names, but only one is the 'prefered' name. The
378 priority is used to select which name is the 'best'.
379
380 Highest precedence is given to core GL name. ARB extension
381 names have the next highest, followed by EXT extension names.
382 Vendor extension names are the lowest.
383 """
384
385 if self.name.endswith( "_BIT" ):
386 bias = 1
387 else:
388 bias = 0
389
390 if self.category.startswith( "GL_VERSION_" ):
391 priority = 0
392 elif self.category.startswith( "GL_ARB_" ):
393 priority = 2
394 elif self.category.startswith( "GL_EXT_" ):
395 priority = 4
396 else:
397 priority = 6
398
399 return priority + bias
400
401
402
403class gl_parameter:
404 def __init__(self, element, context):
405 self.name = element.nsProp( "name", None )
406
407 ts = element.nsProp( "type", None )
408 self.type_expr = typeexpr.type_expression( ts, context )
409
410 temp = element.nsProp( "variable_param", None )
411 if temp:
412 self.count_parameter_list = temp.split( ' ' )
413 else:
414 self.count_parameter_list = []
415
416 # The count tag can be either a numeric string or the name of
417 # a variable. If it is the name of a variable, the int(c)
418 # statement will throw an exception, and the except block will
419 # take over.
420
421 c = element.nsProp( "count", None )
422 try:
423 count = int(c)
424 self.count = count
425 self.counter = None
426 except Exception,e:
427 count = 1
428 self.count = 0
429 self.counter = c
430
431 self.count_scale = int(element.nsProp( "count_scale", None ))
432
433 elements = (count * self.count_scale)
434 if elements == 1:
435 elements = 0
436
437 #if ts == "GLdouble":
438 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
439 # print '/* # elements = %u */' % (elements)
440 self.type_expr.set_elements( elements )
441 #if ts == "GLdouble":
442 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
443
Brian Paul9540c9c2006-11-22 16:01:48 +0000444 self.is_client_only = is_attr_true( element, 'client_only' )
445 self.is_counter = is_attr_true( element, 'counter' )
446 self.is_output = is_attr_true( element, 'output' )
Ian Romanick66a55482005-06-21 23:42:43 +0000447
448
449 # Pixel data has special parameters.
450
451 self.width = element.nsProp('img_width', None)
452 self.height = element.nsProp('img_height', None)
453 self.depth = element.nsProp('img_depth', None)
454 self.extent = element.nsProp('img_extent', None)
455
456 self.img_xoff = element.nsProp('img_xoff', None)
457 self.img_yoff = element.nsProp('img_yoff', None)
458 self.img_zoff = element.nsProp('img_zoff', None)
459 self.img_woff = element.nsProp('img_woff', None)
460
461 self.img_format = element.nsProp('img_format', None)
462 self.img_type = element.nsProp('img_type', None)
463 self.img_target = element.nsProp('img_target', None)
464
465 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
466 self.img_null_flag = is_attr_true( element, 'img_null_flag' )
467 self.img_send_null = is_attr_true( element, 'img_send_null' )
468
Ian Romanick0f733022008-12-09 14:43:09 -0800469 self.is_padding = is_attr_true( element, 'padding' )
Ian Romanick66a55482005-06-21 23:42:43 +0000470 return
471
472
473 def compatible(self, other):
474 return 1
475
476
477 def is_array(self):
478 return self.is_pointer()
479
480
481 def is_pointer(self):
482 return self.type_expr.is_pointer()
483
484
485 def is_image(self):
486 if self.width:
487 return 1
488 else:
489 return 0
490
491
492 def is_variable_length(self):
493 return len(self.count_parameter_list) or self.counter
494
495
496 def is_64_bit(self):
497 count = self.type_expr.get_element_count()
498 if count:
499 if (self.size() / count) == 8:
500 return 1
501 else:
502 if self.size() == 8:
503 return 1
504
505 return 0
506
507
508 def string(self):
509 return self.type_expr.original_string + " " + self.name
510
511
512 def type_string(self):
513 return self.type_expr.original_string
514
515
516 def get_base_type_string(self):
517 return self.type_expr.get_base_name()
518
519
520 def get_dimensions(self):
521 if not self.width:
522 return [ 0, "0", "0", "0", "0" ]
523
524 dim = 1
525 w = self.width
526 h = "1"
527 d = "1"
528 e = "1"
529
530 if self.height:
531 dim = 2
532 h = self.height
533
534 if self.depth:
535 dim = 3
536 d = self.depth
537
538 if self.extent:
539 dim = 4
540 e = self.extent
541
542 return [ dim, w, h, d, e ]
543
544
545 def get_stack_size(self):
546 return self.type_expr.get_stack_size()
547
548
549 def size(self):
550 if self.is_image():
551 return 0
552 else:
553 return self.type_expr.get_element_size()
554
555
556 def get_element_count(self):
557 c = self.type_expr.get_element_count()
558 if c == 0:
559 return 1
560
561 return c
562
563
564 def size_string(self, use_parens = 1):
565 s = self.size()
566 if self.counter or self.count_parameter_list:
567 list = [ "compsize" ]
568
569 if self.counter and self.count_parameter_list:
570 list.append( self.counter )
571 elif self.counter:
572 list = [ self.counter ]
573
574 if s > 1:
575 list.append( str(s) )
576
577 if len(list) > 1 and use_parens :
578 return "(%s)" % (string.join(list, " * "))
579 else:
580 return string.join(list, " * ")
581
582 elif self.is_image():
583 return "compsize"
584 else:
585 return str(s)
586
587
588 def format_string(self):
589 if self.type_expr.original_string == "GLenum":
590 return "0x%x"
591 else:
592 return self.type_expr.format_string()
593
594
595
596class 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
Ian Romanick5aafea02005-06-24 18:35:31 +0000605 self.initialized = 0
Ian Romanick66a55482005-06-21 23:42:43 +0000606 self.images = []
607
Ian Romanickbf83e652006-08-24 20:14:45 +0000608 self.assign_offset = 0
609
Ian Romanick7e9737b2006-08-26 21:26:55 +0000610 self.static_entry_points = []
611
Ian Romanick5aafea02005-06-24 18:35:31 +0000612 # Track the parameter string (for the function prototype)
613 # for each entry-point. This is done because some functions
614 # change their prototype slightly when promoted from extension
615 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
616 # are good examples of this. Scripts that need to generate
617 # code for these differing aliases need to real prototype
618 # for each entry-point. Otherwise, they may generate code
619 # that won't compile.
620
621 self.parameter_strings = {}
622
Ian Romanick66a55482005-06-21 23:42:43 +0000623 self.process_element( element )
624
625 return
626
627
628 def process_element(self, element):
629 name = element.nsProp( "name", None )
630 alias = element.nsProp( "alias", None )
631
Ian Romanick7e9737b2006-08-26 21:26:55 +0000632 if is_attr_true(element, "static_dispatch"):
633 self.static_entry_points.append(name)
Ian Romanick4e4b5f42006-08-22 16:34:38 +0000634
Ian Romanick66a55482005-06-21 23:42:43 +0000635 self.entry_points.append( name )
636 if alias:
637 true_name = alias
638 else:
639 true_name = name
640
641 # Only try to set the offset when a non-alias
642 # entry-point is being processes.
643
644 offset = element.nsProp( "offset", None )
645 if offset:
646 try:
647 o = int( offset )
648 self.offset = o
649 except Exception, e:
650 self.offset = -1
Ian Romanickbf83e652006-08-24 20:14:45 +0000651 if offset == "assign":
652 self.assign_offset = 1
Ian Romanick66a55482005-06-21 23:42:43 +0000653
654
655 if not self.name:
656 self.name = true_name
657 elif self.name != true_name:
658 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
659
660
661 # There are two possible cases. The first time an entry-point
Ian Romanick5aafea02005-06-24 18:35:31 +0000662 # with data is seen, self.initialized will be 0. On that
Ian Romanick66a55482005-06-21 23:42:43 +0000663 # pass, we just fill in the data. The next time an
Ian Romanick5aafea02005-06-24 18:35:31 +0000664 # entry-point with data is seen, self.initialized will be 1.
Ian Romanick66a55482005-06-21 23:42:43 +0000665 # On that pass we have to make that the new values match the
666 # valuse from the previous entry-point.
667
Ian Romanick5aafea02005-06-24 18:35:31 +0000668 parameters = []
669 return_type = "void"
Ian Romanick66a55482005-06-21 23:42:43 +0000670 child = element.children
Ian Romanick5aafea02005-06-24 18:35:31 +0000671 while child:
672 if child.type == "element":
673 if child.name == "return":
674 return_type = child.nsProp( "type", None )
675 elif child.name == "param":
676 param = self.context.factory.create_item( "parameter", child, self.context)
677 parameters.append( param )
Ian Romanick66a55482005-06-21 23:42:43 +0000678
Ian Romanick5aafea02005-06-24 18:35:31 +0000679 child = child.next
Ian Romanick66a55482005-06-21 23:42:43 +0000680
Ian Romanick5aafea02005-06-24 18:35:31 +0000681
682 if self.initialized:
683 if self.return_type != return_type:
684 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
Ian Romanick66a55482005-06-21 23:42:43 +0000685
686 if len(parameters) != len(self.parameters):
687 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
688
689 for j in range(0, len(parameters)):
690 p1 = parameters[j]
691 p2 = self.parameters[j]
692 if not p1.compatible( p2 ):
693 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))
694
695
Ian Romanick5aafea02005-06-24 18:35:31 +0000696 if true_name == name or not self.initialized:
697 self.return_type = return_type
698 self.parameters = parameters
Ian Romanick66a55482005-06-21 23:42:43 +0000699
Ian Romanick66a55482005-06-21 23:42:43 +0000700 for param in self.parameters:
701 if param.is_image():
702 self.images.append( param )
703
704 if element.children:
Ian Romanick5aafea02005-06-24 18:35:31 +0000705 self.initialized = 1
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000706 self.parameter_strings[name] = create_parameter_string(parameters, 1)
Ian Romanick5aafea02005-06-24 18:35:31 +0000707 else:
708 self.parameter_strings[name] = None
Ian Romanick66a55482005-06-21 23:42:43 +0000709
710 return
711
712
713 def get_images(self):
714 """Return potentially empty list of input images."""
715 return self.images
716
717
718 def parameterIterator(self):
719 return self.parameters.__iter__();
720
721
Ian Romanick5aafea02005-06-24 18:35:31 +0000722 def get_parameter_string(self, entrypoint = None):
723 if entrypoint:
724 s = self.parameter_strings[ entrypoint ]
725 if s:
726 return s
727
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000728 return create_parameter_string( self.parameters, 1 )
Ian Romanick66a55482005-06-21 23:42:43 +0000729
Ian Romanickf3f51bc2006-10-11 22:37:14 +0000730 def get_called_parameter_string(self):
731 p_string = ""
732 comma = ""
733
734 for p in self.parameterIterator():
735 p_string = p_string + comma + p.name
736 comma = ", "
737
738 return p_string
739
740
Chia-I Wu6418f832009-10-20 14:32:39 +0800741 def is_abi(self):
742 return (self.offset >= 0 and not self.assign_offset)
743
Ian Romanick7e9737b2006-08-26 21:26:55 +0000744 def is_static_entry_point(self, name):
745 return name in self.static_entry_points
746
Ian Romanick258751f2006-08-28 17:40:45 +0000747 def dispatch_name(self):
748 if self.name in self.static_entry_points:
749 return self.name
750 else:
751 return "_dispatch_stub_%u" % (self.offset)
752
753 def static_name(self, name):
754 if name in self.static_entry_points:
755 return name
756 else:
757 return "_dispatch_stub_%u" % (self.offset)
758
Ian Romanick66a55482005-06-21 23:42:43 +0000759
760class gl_item_factory:
761 """Factory to create objects derived from gl_item."""
762
763 def create_item(self, item_name, element, context):
764 if item_name == "function":
765 return gl_function(element, context)
766 if item_name == "type":
767 return gl_type(element, context)
768 elif item_name == "enum":
769 return gl_enum(element, context)
770 elif item_name == "parameter":
771 return gl_parameter(element, context)
772 elif item_name == "api":
773 return gl_api(self)
774 else:
775 return None
776
777
778class gl_api:
779 def __init__(self, factory):
780 self.functions_by_name = {}
781 self.enums_by_name = {}
782 self.types_by_name = {}
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000783
Ian Romanick66a55482005-06-21 23:42:43 +0000784 self.category_dict = {}
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000785 self.categories = [{}, {}, {}, {}]
Ian Romanick66a55482005-06-21 23:42:43 +0000786
787 self.factory = factory
788
Ian Romanickbf83e652006-08-24 20:14:45 +0000789 self.next_offset = 0
790
Ian Romanick66a55482005-06-21 23:42:43 +0000791 typeexpr.create_initial_types()
792 return
793
794
795 def process_element(self, doc):
796 element = doc.children
797 while element.type != "element" or element.name != "OpenGLAPI":
798 element = element.next
799
800 if element:
801 self.process_OpenGLAPI(element)
802 return
803
804
805 def process_OpenGLAPI(self, element):
806 child = element.children
807 while child:
808 if child.type == "element":
809 if child.name == "category":
810 self.process_category( child )
811 elif child.name == "OpenGLAPI":
812 self.process_OpenGLAPI( child )
813
814 child = child.next
815
816 return
817
818
819 def process_category(self, cat):
820 cat_name = cat.nsProp( "name", None )
821 cat_number = cat.nsProp( "number", None )
822
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000823 [cat_type, key] = classify_category(cat_name, cat_number)
824 self.categories[cat_type][key] = [cat_name, cat_number]
825
Ian Romanick66a55482005-06-21 23:42:43 +0000826 child = cat.children
827 while child:
828 if child.type == "element":
829 if child.name == "function":
830 func_name = real_function_name( child )
831
Ian Romanick5aafea02005-06-24 18:35:31 +0000832 temp_name = child.nsProp( "name", None )
833 self.category_dict[ temp_name ] = [cat_name, cat_number]
834
Ian Romanick66a55482005-06-21 23:42:43 +0000835 if self.functions_by_name.has_key( func_name ):
836 func = self.functions_by_name[ func_name ]
837 func.process_element( child )
838 else:
839 func = self.factory.create_item( "function", child, self )
840 self.functions_by_name[ func_name ] = func
841
Ian Romanickbf83e652006-08-24 20:14:45 +0000842 if func.offset >= self.next_offset:
843 self.next_offset = func.offset + 1
844
Ian Romanick66a55482005-06-21 23:42:43 +0000845
846 elif child.name == "enum":
847 enum = self.factory.create_item( "enum", child, self )
848 self.enums_by_name[ enum.name ] = enum
849 elif child.name == "type":
850 t = self.factory.create_item( "type", child, self )
851 self.types_by_name[ "GL" + t.name ] = t
852
853
854 child = child.next
855
856 return
857
858
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000859 def functionIterateByCategory(self, cat = None):
860 """Iterate over functions by category.
861
862 If cat is None, all known functions are iterated in category
863 order. See classify_category for details of the ordering.
864 Within a category, functions are sorted by name. If cat is
865 not None, then only functions in that category are iterated.
866 """
867 lists = [{}, {}, {}, {}]
868
869 for func in self.functionIterateAll():
870 [cat_name, cat_number] = self.category_dict[func.name]
871
872 if (cat == None) or (cat == cat_name):
873 [func_cat_type, key] = classify_category(cat_name, cat_number)
874
875 if not lists[func_cat_type].has_key(key):
876 lists[func_cat_type][key] = {}
877
878 lists[func_cat_type][key][func.name] = func
879
880
881 functions = []
882 for func_cat_type in range(0,4):
883 keys = lists[func_cat_type].keys()
884 keys.sort()
885
886 for key in keys:
887 names = lists[func_cat_type][key].keys()
888 names.sort()
889
890 for name in names:
891 functions.append(lists[func_cat_type][key][name])
892
893 return functions.__iter__()
894
895
Ian Romanick66a55482005-06-21 23:42:43 +0000896 def functionIterateByOffset(self):
897 max_offset = -1
898 for func in self.functions_by_name.itervalues():
899 if func.offset > max_offset:
900 max_offset = func.offset
901
902
903 temp = [None for i in range(0, max_offset + 1)]
904 for func in self.functions_by_name.itervalues():
905 if func.offset != -1:
906 temp[ func.offset ] = func
907
908
909 list = []
910 for i in range(0, max_offset + 1):
911 if temp[i]:
912 list.append(temp[i])
913
914 return list.__iter__();
915
916
917 def functionIterateAll(self):
918 return self.functions_by_name.itervalues()
919
920
921 def enumIterateByName(self):
922 keys = self.enums_by_name.keys()
923 keys.sort()
924
925 list = []
926 for enum in keys:
927 list.append( self.enums_by_name[ enum ] )
928
929 return list.__iter__()
930
931
Ian Romanickeaeaaf62006-10-04 20:45:59 +0000932 def categoryIterate(self):
933 """Iterate over categories.
934
935 Iterate over all known categories in the order specified by
936 classify_category. Each iterated value is a tuple of the
937 name and number (which may be None) of the category.
938 """
939
940 list = []
941 for cat_type in range(0,4):
942 keys = self.categories[cat_type].keys()
943 keys.sort()
944
945 for key in keys:
946 list.append(self.categories[cat_type][key])
947
948 return list.__iter__()
949
950
Ian Romanick66a55482005-06-21 23:42:43 +0000951 def get_category_for_name( self, name ):
952 if self.category_dict.has_key(name):
953 return self.category_dict[name]
954 else:
955 return ["<unknown category>", None]
956
957
958 def typeIterate(self):
959 return self.types_by_name.itervalues()
960
961
962 def find_type( self, type_name ):
963 if type_name in self.types_by_name:
964 return self.types_by_name[ type_name ].type_expr
965 else:
966 print "Unable to find base type matching \"%s\"." % (type_name)
967 return None