blob: 868a7cd1bda404d1c13dc4adcbd9cc6297997f29 [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.
47 #
48 # To bring some sanity to the generated offsets, we group all
49 # functions into four groups. The groups have offsets assigned to
50 # their functions in order. The groups are:
51 #
52 # 1. Core GL versions, sorted by version number.
53 # 2. ARB extensions, sorted by extension number.
54 # 3. Non-ARB extensions, sorted by extension number.
55 # 4. Un-numbered, non-ARB extensions, sorted by extension name.
56
57 lists = [{}, {}, {}, {}]
58
59 for func in api.functionIterateAll():
60 if func.assign_offset:
61 [cat_name, cat_number] = api.category_dict[func.name]
62
63 try:
64 core_version = float(cat_name)
65 except Exception,e:
66 core_version = 0.0
67
68 if core_version > 0.0:
69 func_cat_type = 0
70 key = cat_name
71 elif cat_name.startswith( "GL_ARB_" ):
72 func_cat_type = 1
73 key = int(cat_number)
74 else:
75 if cat_number != None:
76 func_cat_type = 2
77 key = int(cat_number)
78 else:
79 func_cat_type = 3
80 key = cat_name
81
82 if not lists[func_cat_type].has_key(key):
83 lists[func_cat_type][key] = {}
84
85 lists[func_cat_type][key][func.name] = func
86
87 for func_cat_type in range(0,4):
88 keys = lists[func_cat_type].keys()
89 keys.sort()
90
91 for key in keys:
92 names = lists[func_cat_type][key].keys()
93 names.sort()
94
95 for name in names:
96 func = lists[func_cat_type][key][name]
97 func.offset = api.next_offset;
98 api.next_offset += 1
99
Ian Romanick66a55482005-06-21 23:42:43 +0000100 doc.freeDoc()
101
102 return api
103
104
105def is_attr_true( element, name ):
Ian Romanick73b4c1b2005-04-14 23:00:34 +0000106 """Read a name value from an element's attributes.
107
108 The value read from the attribute list must be either 'true' or
109 'false'. If the value is 'false', zero will be returned. If the
110 value is 'true', non-zero will be returned. An exception will be
111 raised for any other value."""
112
Ian Romanick66a55482005-06-21 23:42:43 +0000113 value = element.nsProp( name, None )
Ian Romanick73b4c1b2005-04-14 23:00:34 +0000114 if value == "true":
115 return 1
116 elif value == "false":
117 return 0
118 else:
119 raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name))
120
121
Ian Romanick66a55482005-06-21 23:42:43 +0000122class gl_print_base:
123 """Base class of all API pretty-printers.
Ian Romanick93d2d542005-04-18 19:42:23 +0000124
Ian Romanick66a55482005-06-21 23:42:43 +0000125 In the model-view-controller pattern, this is the view. Any derived
126 class will want to over-ride the printBody, printRealHader, and
127 printRealFooter methods. Some derived classes may want to over-ride
128 printHeader and printFooter, or even Print (though this is unlikely).
Ian Romanick93d2d542005-04-18 19:42:23 +0000129 """
Ian Romanickd03ab102005-04-18 21:30:20 +0000130
Ian Romanick73f59b02004-05-18 18:33:40 +0000131 def __init__(self):
Ian Romanick66a55482005-06-21 23:42:43 +0000132 # Name of the script that is generating the output file.
133 # Every derived class should set this to the name of its
134 # source file.
135
136 self.name = "a"
137
138
139 # License on the *generated* source file. This may differ
140 # from the license on the script that is generating the file.
141 # Every derived class should set this to some reasonable
142 # value.
143 #
144 # See license.py for an example of a reasonable value.
145
146 self.license = "The license for this file is unspecified."
147
148
149 # The header_tag is the name of the C preprocessor define
150 # used to prevent multiple inclusion. Typically only
151 # generated C header files need this to be set. Setting it
152 # causes code to be generated automatically in printHeader
153 # and printFooter.
154
Ian Romanick16c3c742005-01-28 19:00:54 +0000155 self.header_tag = None
Ian Romanick66a55482005-06-21 23:42:43 +0000156
157
158 # List of file-private defines that must be undefined at the
159 # end of the file. This can be used in header files to define
160 # names for use in the file, then undefine them at the end of
161 # the header file.
162
Ian Romanickc2803582005-02-01 00:28:47 +0000163 self.undef_list = []
Ian Romanick66a55482005-06-21 23:42:43 +0000164 return
Ian Romanick73f59b02004-05-18 18:33:40 +0000165
Ian Romanicka9d033c2004-05-19 23:33:08 +0000166
Ian Romanick66a55482005-06-21 23:42:43 +0000167 def Print(self, api):
168 self.printHeader()
169 self.printBody(api)
170 self.printFooter()
Ian Romanick73f59b02004-05-18 18:33:40 +0000171 return
172
Ian Romanicka9d033c2004-05-19 23:33:08 +0000173
Ian Romanick73f59b02004-05-18 18:33:40 +0000174 def printHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000175 """Print the header associated with all files and call the printRealHeader method."""
176
Ian Romanick73f59b02004-05-18 18:33:40 +0000177 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
178 % (self.name)
179 print ''
180 print '/*'
181 print ' * ' + self.license.replace('\n', '\n * ')
182 print ' */'
183 print ''
Ian Romanick16c3c742005-01-28 19:00:54 +0000184 if self.header_tag:
185 print '#if !defined( %s )' % (self.header_tag)
186 print '# define %s' % (self.header_tag)
187 print ''
Ian Romanick73f59b02004-05-18 18:33:40 +0000188 self.printRealHeader();
189 return
190
Ian Romanicka9d033c2004-05-19 23:33:08 +0000191
Ian Romanick73f59b02004-05-18 18:33:40 +0000192 def printFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000193 """Print the header associated with all files and call the printRealFooter method."""
194
Ian Romanick73f59b02004-05-18 18:33:40 +0000195 self.printRealFooter()
Ian Romanick66a55482005-06-21 23:42:43 +0000196
197 if self.undef_list:
198 print ''
199 for u in self.undef_list:
200 print "# undef %s" % (u)
201
Ian Romanick16c3c742005-01-28 19:00:54 +0000202 if self.header_tag:
Ian Romanickc2803582005-02-01 00:28:47 +0000203 print ''
204 print '#endif /* !defined( %s ) */' % (self.header_tag)
Ian Romanick73f59b02004-05-18 18:33:40 +0000205
206
Ian Romanick73f59b02004-05-18 18:33:40 +0000207 def printRealHeader(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000208 """Print the "real" header for the created file.
209
210 In the base class, this function is empty. All derived
211 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000212 return
213
Ian Romanicka9d033c2004-05-19 23:33:08 +0000214
Ian Romanick73f59b02004-05-18 18:33:40 +0000215 def printRealFooter(self):
Ian Romanicka9d033c2004-05-19 23:33:08 +0000216 """Print the "real" footer for the created file.
217
218 In the base class, this function is empty. All derived
219 classes should over-ride this function."""
Ian Romanick73f59b02004-05-18 18:33:40 +0000220 return
Ian Romanick66a55482005-06-21 23:42:43 +0000221
222
223 def printPure(self):
224 """Conditionally define `PURE' function attribute.
225
226 Conditionally defines a preprocessor macro `PURE' that wraps
227 GCC's `pure' function attribute. The conditional code can be
228 easilly adapted to other compilers that support a similar
229 feature.
230
231 The name is also added to the file's undef_list.
232 """
233 self.undef_list.append("PURE")
234 print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
235# define PURE __attribute__((pure))
236# else
237# define PURE
238# endif"""
239 return
240
241
242 def printFastcall(self):
243 """Conditionally define `FASTCALL' function attribute.
244
245 Conditionally defines a preprocessor macro `FASTCALL' that
246 wraps GCC's `fastcall' function attribute. The conditional
247 code can be easilly adapted to other compilers that support a
248 similar feature.
249
250 The name is also added to the file's undef_list.
251 """
252
253 self.undef_list.append("FASTCALL")
Brian Paulf468dfd2005-10-20 22:51:50 +0000254 print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
255# define FASTCALL __attribute__((fastcall))
256# else
257# define FASTCALL
258# endif"""
Ian Romanick66a55482005-06-21 23:42:43 +0000259 return
260
261
262 def printVisibility(self, S, s):
263 """Conditionally define visibility function attribute.
264
265 Conditionally defines a preprocessor macro name S that wraps
266 GCC's visibility function attribute. The visibility used is
267 the parameter s. The conditional code can be easilly adapted
268 to other compilers that support a similar feature.
269
270 The name is also added to the file's undef_list.
271 """
272
273 self.undef_list.append(S)
Adam Jacksonca1ac982005-08-26 17:50:39 +0000274 print """# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
Ian Romanick66a55482005-06-21 23:42:43 +0000275# define %s __attribute__((visibility("%s")))
276# else
277# define %s
278# endif""" % (S, s, S)
279 return
280
281
282 def printNoinline(self):
283 """Conditionally define `NOINLINE' function attribute.
284
285 Conditionally defines a preprocessor macro `NOINLINE' that
286 wraps GCC's `noinline' function attribute. The conditional
287 code can be easilly adapted to other compilers that support a
288 similar feature.
289
290 The name is also added to the file's undef_list.
291 """
292
293 self.undef_list.append("NOINLINE")
294 print """# if defined(__GNUC__)
295# define NOINLINE __attribute__((noinline))
296# else
297# define NOINLINE
298# endif"""
299 return
300
301
Ian Romanick66a55482005-06-21 23:42:43 +0000302def real_function_name(element):
303 name = element.nsProp( "name", None )
304 alias = element.nsProp( "alias", None )
305
306 if alias:
307 return alias
308 else:
309 return name
310
311
Ian Romanick5aafea02005-06-24 18:35:31 +0000312def real_category_name(c):
313 if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
314 return "GL_VERSION_" + c.replace(".", "_")
315 else:
316 return c
317
318
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000319def create_parameter_string(parameters, include_names):
Ian Romanick5aafea02005-06-24 18:35:31 +0000320 """Create a parameter string from a list of gl_parameters."""
321
322 list = []
323 for p in parameters:
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000324 if include_names:
325 list.append( p.string() )
326 else:
327 list.append( p.type_string() )
Ian Romanick5aafea02005-06-24 18:35:31 +0000328
329 if len(list) == 0: list = ["void"]
330
331 return string.join(list, ", ")
332
333
Ian Romanick66a55482005-06-21 23:42:43 +0000334class gl_item:
335 def __init__(self, element, context):
336 self.context = context
Ian Romanick66a55482005-06-21 23:42:43 +0000337 self.name = element.nsProp( "name", None )
Ian Romanick5aafea02005-06-24 18:35:31 +0000338 self.category = real_category_name( element.parent.nsProp( "name", None ) )
Ian Romanick66a55482005-06-21 23:42:43 +0000339 return
340
341
342class gl_type( gl_item ):
343 def __init__(self, element, context):
344 gl_item.__init__(self, element, context)
345 self.size = int( element.nsProp( "size", None ), 0 )
346
347 te = typeexpr.type_expression( None )
348 tn = typeexpr.type_node()
349 tn.size = int( element.nsProp( "size", None ), 0 )
350 tn.integer = not is_attr_true( element, "float" )
351 tn.unsigned = is_attr_true( element, "unsigned" )
352 tn.name = "GL" + self.name
353 te.set_base_type_node( tn )
354
355 self.type_expr = te
356 return
357
358
359 def get_type_expression(self):
360 return self.type_expr
361
362
363class gl_enum( gl_item ):
364 def __init__(self, element, context):
365 gl_item.__init__(self, element, context)
366 self.value = int( element.nsProp( "value", None ), 0 )
367
368 temp = element.nsProp( "count", None )
369 if not temp or temp == "?":
370 self.default_count = -1
371 else:
372 try:
373 c = int(temp)
374 except Exception,e:
375 raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n))
376
377 self.default_count = c
378
379 return
380
381
382 def priority(self):
383 """Calculate a 'priority' for this enum name.
384
385 When an enum is looked up by number, there may be many
386 possible names, but only one is the 'prefered' name. The
387 priority is used to select which name is the 'best'.
388
389 Highest precedence is given to core GL name. ARB extension
390 names have the next highest, followed by EXT extension names.
391 Vendor extension names are the lowest.
392 """
393
394 if self.name.endswith( "_BIT" ):
395 bias = 1
396 else:
397 bias = 0
398
399 if self.category.startswith( "GL_VERSION_" ):
400 priority = 0
401 elif self.category.startswith( "GL_ARB_" ):
402 priority = 2
403 elif self.category.startswith( "GL_EXT_" ):
404 priority = 4
405 else:
406 priority = 6
407
408 return priority + bias
409
410
411
412class gl_parameter:
413 def __init__(self, element, context):
414 self.name = element.nsProp( "name", None )
415
416 ts = element.nsProp( "type", None )
417 self.type_expr = typeexpr.type_expression( ts, context )
418
419 temp = element.nsProp( "variable_param", None )
420 if temp:
421 self.count_parameter_list = temp.split( ' ' )
422 else:
423 self.count_parameter_list = []
424
425 # The count tag can be either a numeric string or the name of
426 # a variable. If it is the name of a variable, the int(c)
427 # statement will throw an exception, and the except block will
428 # take over.
429
430 c = element.nsProp( "count", None )
431 try:
432 count = int(c)
433 self.count = count
434 self.counter = None
435 except Exception,e:
436 count = 1
437 self.count = 0
438 self.counter = c
439
440 self.count_scale = int(element.nsProp( "count_scale", None ))
441
442 elements = (count * self.count_scale)
443 if elements == 1:
444 elements = 0
445
446 #if ts == "GLdouble":
447 # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size())
448 # print '/* # elements = %u */' % (elements)
449 self.type_expr.set_elements( elements )
450 #if ts == "GLdouble":
451 # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
452
453 self.is_counter = is_attr_true( element, 'counter' )
454 self.is_output = is_attr_true( element, 'output' )
455
456
457 # Pixel data has special parameters.
458
459 self.width = element.nsProp('img_width', None)
460 self.height = element.nsProp('img_height', None)
461 self.depth = element.nsProp('img_depth', None)
462 self.extent = element.nsProp('img_extent', None)
463
464 self.img_xoff = element.nsProp('img_xoff', None)
465 self.img_yoff = element.nsProp('img_yoff', None)
466 self.img_zoff = element.nsProp('img_zoff', None)
467 self.img_woff = element.nsProp('img_woff', None)
468
469 self.img_format = element.nsProp('img_format', None)
470 self.img_type = element.nsProp('img_type', None)
471 self.img_target = element.nsProp('img_target', None)
472
473 self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' )
474 self.img_null_flag = is_attr_true( element, 'img_null_flag' )
475 self.img_send_null = is_attr_true( element, 'img_send_null' )
476
477 return
478
479
480 def compatible(self, other):
481 return 1
482
483
484 def is_array(self):
485 return self.is_pointer()
486
487
488 def is_pointer(self):
489 return self.type_expr.is_pointer()
490
491
492 def is_image(self):
493 if self.width:
494 return 1
495 else:
496 return 0
497
498
499 def is_variable_length(self):
500 return len(self.count_parameter_list) or self.counter
501
502
503 def is_64_bit(self):
504 count = self.type_expr.get_element_count()
505 if count:
506 if (self.size() / count) == 8:
507 return 1
508 else:
509 if self.size() == 8:
510 return 1
511
512 return 0
513
514
515 def string(self):
516 return self.type_expr.original_string + " " + self.name
517
518
519 def type_string(self):
520 return self.type_expr.original_string
521
522
523 def get_base_type_string(self):
524 return self.type_expr.get_base_name()
525
526
527 def get_dimensions(self):
528 if not self.width:
529 return [ 0, "0", "0", "0", "0" ]
530
531 dim = 1
532 w = self.width
533 h = "1"
534 d = "1"
535 e = "1"
536
537 if self.height:
538 dim = 2
539 h = self.height
540
541 if self.depth:
542 dim = 3
543 d = self.depth
544
545 if self.extent:
546 dim = 4
547 e = self.extent
548
549 return [ dim, w, h, d, e ]
550
551
552 def get_stack_size(self):
553 return self.type_expr.get_stack_size()
554
555
556 def size(self):
557 if self.is_image():
558 return 0
559 else:
560 return self.type_expr.get_element_size()
561
562
563 def get_element_count(self):
564 c = self.type_expr.get_element_count()
565 if c == 0:
566 return 1
567
568 return c
569
570
571 def size_string(self, use_parens = 1):
572 s = self.size()
573 if self.counter or self.count_parameter_list:
574 list = [ "compsize" ]
575
576 if self.counter and self.count_parameter_list:
577 list.append( self.counter )
578 elif self.counter:
579 list = [ self.counter ]
580
581 if s > 1:
582 list.append( str(s) )
583
584 if len(list) > 1 and use_parens :
585 return "(%s)" % (string.join(list, " * "))
586 else:
587 return string.join(list, " * ")
588
589 elif self.is_image():
590 return "compsize"
591 else:
592 return str(s)
593
594
595 def format_string(self):
596 if self.type_expr.original_string == "GLenum":
597 return "0x%x"
598 else:
599 return self.type_expr.format_string()
600
601
602
603class gl_function( gl_item ):
604 def __init__(self, element, context):
605 self.context = context
606 self.name = None
607
608 self.entry_points = []
609 self.return_type = "void"
610 self.parameters = []
611 self.offset = -1
Ian Romanick5aafea02005-06-24 18:35:31 +0000612 self.initialized = 0
Ian Romanick66a55482005-06-21 23:42:43 +0000613 self.images = []
614
Ian Romanickbf83e652006-08-24 20:14:45 +0000615 self.assign_offset = 0
616
Ian Romanick7e9737b2006-08-26 21:26:55 +0000617 self.static_entry_points = []
618
Ian Romanick5aafea02005-06-24 18:35:31 +0000619 # Track the parameter string (for the function prototype)
620 # for each entry-point. This is done because some functions
621 # change their prototype slightly when promoted from extension
622 # to ARB extension to core. glTexImage3DEXT and glTexImage3D
623 # are good examples of this. Scripts that need to generate
624 # code for these differing aliases need to real prototype
625 # for each entry-point. Otherwise, they may generate code
626 # that won't compile.
627
628 self.parameter_strings = {}
629
Ian Romanick66a55482005-06-21 23:42:43 +0000630 self.process_element( element )
631
632 return
633
634
635 def process_element(self, element):
636 name = element.nsProp( "name", None )
637 alias = element.nsProp( "alias", None )
638
Ian Romanick7e9737b2006-08-26 21:26:55 +0000639 if is_attr_true(element, "static_dispatch"):
640 self.static_entry_points.append(name)
Ian Romanick4e4b5f42006-08-22 16:34:38 +0000641
Ian Romanick66a55482005-06-21 23:42:43 +0000642 self.entry_points.append( name )
643 if alias:
644 true_name = alias
645 else:
646 true_name = name
647
648 # Only try to set the offset when a non-alias
649 # entry-point is being processes.
650
651 offset = element.nsProp( "offset", None )
652 if offset:
653 try:
654 o = int( offset )
655 self.offset = o
656 except Exception, e:
657 self.offset = -1
Ian Romanickbf83e652006-08-24 20:14:45 +0000658 if offset == "assign":
659 self.assign_offset = 1
Ian Romanick66a55482005-06-21 23:42:43 +0000660
661
662 if not self.name:
663 self.name = true_name
664 elif self.name != true_name:
665 raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
666
667
668 # There are two possible cases. The first time an entry-point
Ian Romanick5aafea02005-06-24 18:35:31 +0000669 # with data is seen, self.initialized will be 0. On that
Ian Romanick66a55482005-06-21 23:42:43 +0000670 # pass, we just fill in the data. The next time an
Ian Romanick5aafea02005-06-24 18:35:31 +0000671 # entry-point with data is seen, self.initialized will be 1.
Ian Romanick66a55482005-06-21 23:42:43 +0000672 # On that pass we have to make that the new values match the
673 # valuse from the previous entry-point.
674
Ian Romanick5aafea02005-06-24 18:35:31 +0000675 parameters = []
676 return_type = "void"
Ian Romanick66a55482005-06-21 23:42:43 +0000677 child = element.children
Ian Romanick5aafea02005-06-24 18:35:31 +0000678 while child:
679 if child.type == "element":
680 if child.name == "return":
681 return_type = child.nsProp( "type", None )
682 elif child.name == "param":
683 param = self.context.factory.create_item( "parameter", child, self.context)
684 parameters.append( param )
Ian Romanick66a55482005-06-21 23:42:43 +0000685
Ian Romanick5aafea02005-06-24 18:35:31 +0000686 child = child.next
Ian Romanick66a55482005-06-21 23:42:43 +0000687
Ian Romanick5aafea02005-06-24 18:35:31 +0000688
689 if self.initialized:
690 if self.return_type != return_type:
691 raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
Ian Romanick66a55482005-06-21 23:42:43 +0000692
693 if len(parameters) != len(self.parameters):
694 raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
695
696 for j in range(0, len(parameters)):
697 p1 = parameters[j]
698 p2 = self.parameters[j]
699 if not p1.compatible( p2 ):
700 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))
701
702
Ian Romanick5aafea02005-06-24 18:35:31 +0000703 if true_name == name or not self.initialized:
704 self.return_type = return_type
705 self.parameters = parameters
Ian Romanick66a55482005-06-21 23:42:43 +0000706
Ian Romanick66a55482005-06-21 23:42:43 +0000707 for param in self.parameters:
708 if param.is_image():
709 self.images.append( param )
710
711 if element.children:
Ian Romanick5aafea02005-06-24 18:35:31 +0000712 self.initialized = 1
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000713 self.parameter_strings[name] = create_parameter_string(parameters, 1)
Ian Romanick5aafea02005-06-24 18:35:31 +0000714 else:
715 self.parameter_strings[name] = None
Ian Romanick66a55482005-06-21 23:42:43 +0000716
717 return
718
719
720 def get_images(self):
721 """Return potentially empty list of input images."""
722 return self.images
723
724
725 def parameterIterator(self):
726 return self.parameters.__iter__();
727
728
Ian Romanick5aafea02005-06-24 18:35:31 +0000729 def get_parameter_string(self, entrypoint = None):
730 if entrypoint:
731 s = self.parameter_strings[ entrypoint ]
732 if s:
733 return s
734
Ian Romanickf0ff50d2005-07-02 08:29:57 +0000735 return create_parameter_string( self.parameters, 1 )
Ian Romanick66a55482005-06-21 23:42:43 +0000736
Ian Romanick7e9737b2006-08-26 21:26:55 +0000737 def is_static_entry_point(self, name):
738 return name in self.static_entry_points
739
Ian Romanick66a55482005-06-21 23:42:43 +0000740
741class gl_item_factory:
742 """Factory to create objects derived from gl_item."""
743
744 def create_item(self, item_name, element, context):
745 if item_name == "function":
746 return gl_function(element, context)
747 if item_name == "type":
748 return gl_type(element, context)
749 elif item_name == "enum":
750 return gl_enum(element, context)
751 elif item_name == "parameter":
752 return gl_parameter(element, context)
753 elif item_name == "api":
754 return gl_api(self)
755 else:
756 return None
757
758
759class gl_api:
760 def __init__(self, factory):
761 self.functions_by_name = {}
762 self.enums_by_name = {}
763 self.types_by_name = {}
764 self.category_dict = {}
765
766 self.factory = factory
767
Ian Romanickbf83e652006-08-24 20:14:45 +0000768 self.next_offset = 0
769
Ian Romanick66a55482005-06-21 23:42:43 +0000770 typeexpr.create_initial_types()
771 return
772
773
774 def process_element(self, doc):
775 element = doc.children
776 while element.type != "element" or element.name != "OpenGLAPI":
777 element = element.next
778
779 if element:
780 self.process_OpenGLAPI(element)
781 return
782
783
784 def process_OpenGLAPI(self, element):
785 child = element.children
786 while child:
787 if child.type == "element":
788 if child.name == "category":
789 self.process_category( child )
790 elif child.name == "OpenGLAPI":
791 self.process_OpenGLAPI( child )
792
793 child = child.next
794
795 return
796
797
798 def process_category(self, cat):
799 cat_name = cat.nsProp( "name", None )
800 cat_number = cat.nsProp( "number", None )
801
802 child = cat.children
803 while child:
804 if child.type == "element":
805 if child.name == "function":
806 func_name = real_function_name( child )
807
Ian Romanick5aafea02005-06-24 18:35:31 +0000808 temp_name = child.nsProp( "name", None )
809 self.category_dict[ temp_name ] = [cat_name, cat_number]
810
Ian Romanick66a55482005-06-21 23:42:43 +0000811 if self.functions_by_name.has_key( func_name ):
812 func = self.functions_by_name[ func_name ]
813 func.process_element( child )
814 else:
815 func = self.factory.create_item( "function", child, self )
816 self.functions_by_name[ func_name ] = func
817
Ian Romanickbf83e652006-08-24 20:14:45 +0000818 if func.offset >= self.next_offset:
819 self.next_offset = func.offset + 1
820
Ian Romanick66a55482005-06-21 23:42:43 +0000821
822 elif child.name == "enum":
823 enum = self.factory.create_item( "enum", child, self )
824 self.enums_by_name[ enum.name ] = enum
825 elif child.name == "type":
826 t = self.factory.create_item( "type", child, self )
827 self.types_by_name[ "GL" + t.name ] = t
828
829
830 child = child.next
831
832 return
833
834
835 def functionIterateByOffset(self):
836 max_offset = -1
837 for func in self.functions_by_name.itervalues():
838 if func.offset > max_offset:
839 max_offset = func.offset
840
841
842 temp = [None for i in range(0, max_offset + 1)]
843 for func in self.functions_by_name.itervalues():
844 if func.offset != -1:
845 temp[ func.offset ] = func
846
847
848 list = []
849 for i in range(0, max_offset + 1):
850 if temp[i]:
851 list.append(temp[i])
852
853 return list.__iter__();
854
855
856 def functionIterateAll(self):
857 return self.functions_by_name.itervalues()
858
859
860 def enumIterateByName(self):
861 keys = self.enums_by_name.keys()
862 keys.sort()
863
864 list = []
865 for enum in keys:
866 list.append( self.enums_by_name[ enum ] )
867
868 return list.__iter__()
869
870
871 def get_category_for_name( self, name ):
872 if self.category_dict.has_key(name):
873 return self.category_dict[name]
874 else:
875 return ["<unknown category>", None]
876
877
878 def typeIterate(self):
879 return self.types_by_name.itervalues()
880
881
882 def find_type( self, type_name ):
883 if type_name in self.types_by_name:
884 return self.types_by_name[ type_name ].type_expr
885 else:
886 print "Unable to find base type matching \"%s\"." % (type_name)
887 return None