Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 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 
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 = False
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 name in static_data.functions:
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
            if name in static_data.offsets:
689
                self.offset = static_data.offsets[name]
690
            else:
691
                self.offset = -1
692
                self.assign_offset = self.exec_flavor != "skip" or name in static_data.unused_functions
693
 
694
        if not self.name:
695
            self.name = true_name
696
        elif self.name != true_name:
697
            raise RuntimeError("Function true name redefined.  Was %s, now %s." % (self.name, true_name))
698
 
699
 
700
        # There are two possible cases.  The first time an entry-point
701
        # with data is seen, self.initialized will be 0.  On that
702
        # pass, we just fill in the data.  The next time an
703
        # entry-point with data is seen, self.initialized will be 1.
704
        # On that pass we have to make that the new values match the
705
        # valuse from the previous entry-point.
706
 
707
        parameters = []
708
        return_type = "void"
709
        for child in element.getchildren():
710
            if child.tag == "return":
711
                return_type = child.get( "type", "void" )
712
            elif child.tag == "param":
713
                param = self.context.factory.create_parameter(child, self.context)
714
                parameters.append( param )
715
 
716
 
717
        if self.initialized:
718
            if self.return_type != return_type:
719
                raise RuntimeError( "Return type changed in %s.  Was %s, now %s." % (name, self.return_type, return_type))
720
 
721
            if len(parameters) != len(self.parameters):
722
                raise RuntimeError( "Parameter count mismatch in %s.  Was %d, now %d." % (name, len(self.parameters), len(parameters)))
723
 
724
            for j in range(0, len(parameters)):
725
                p1 = parameters[j]
726
                p2 = self.parameters[j]
727
                if not p1.compatible( p2 ):
728
                    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))
729
 
730
 
731
        if true_name == name or not self.initialized:
732
            self.return_type = return_type
733
            self.parameters = parameters
734
 
735
            for param in self.parameters:
736
                if param.is_image():
737
                    self.images.append( param )
738
 
739
        if element.getchildren():
740
            self.initialized = 1
741
            self.entry_point_parameters[name] = parameters
742
        else:
743
            self.entry_point_parameters[name] = []
744
 
745
        return
746
 
747
    def filter_entry_points(self, entry_point_list):
748
        """Filter out entry points not in entry_point_list."""
749
        if not self.initialized:
750
            raise RuntimeError('%s is not initialized yet' % self.name)
751
 
752
        entry_points = []
753
        for ent in self.entry_points:
754
            if ent not in entry_point_list:
755
                if ent in self.static_entry_points:
756
                    self.static_entry_points.remove(ent)
757
                self.entry_point_parameters.pop(ent)
758
            else:
759
                entry_points.append(ent)
760
 
761
        if not entry_points:
762
            raise RuntimeError('%s has no entry point after filtering' % self.name)
763
 
764
        self.entry_points = entry_points
765
        if self.name not in entry_points:
766
            # use the first remaining entry point
767
            self.name = entry_points[0]
768
            self.parameters = self.entry_point_parameters[entry_points[0]]
769
 
770
    def get_images(self):
771
        """Return potentially empty list of input images."""
772
        return self.images
773
 
774
 
775
    def parameterIterator(self, name = None):
776
        if name is not None:
777
            return self.entry_point_parameters[name].__iter__();
778
        else:
779
            return self.parameters.__iter__();
780
 
781
 
782
    def get_parameter_string(self, entrypoint = None):
783
        if entrypoint:
784
            params = self.entry_point_parameters[ entrypoint ]
785
        else:
786
            params = self.parameters
787
 
788
        return create_parameter_string( params, 1 )
789
 
790
    def get_called_parameter_string(self):
791
        p_string = ""
792
        comma = ""
793
 
794
        for p in self.parameterIterator():
795
            if p.is_padding:
796
                continue
797
            p_string = p_string + comma + p.name
798
            comma = ", "
799
 
800
        return p_string
801
 
802
 
803
    def is_abi(self):
804
        return (self.offset >= 0 and not self.assign_offset)
805
 
806
    def is_static_entry_point(self, name):
807
        return name in self.static_entry_points
808
 
809
    def dispatch_name(self):
810
        if self.name in self.static_entry_points:
811
            return self.name
812
        else:
813
            return "_dispatch_stub_%u" % (self.offset)
814
 
815
    def static_name(self, name):
816
        if name in self.static_entry_points:
817
            return name
818
        else:
819
            return "_dispatch_stub_%u" % (self.offset)
820
 
821
    def entry_points_for_api_version(self, api, version = None):
822
        """Return a list of the entry point names for this function
823
        which are supported in the given API (and optionally, version).
824
 
825
        Use the decimal.Decimal type to precisely express non-integer
826
        versions.
827
        """
828
        result = []
829
        for entry_point, api_to_ver in self.entry_point_api_map.iteritems():
830
            if api not in api_to_ver:
831
                continue
832
            if version is not None and version < api_to_ver[api]:
833
                continue
834
            result.append(entry_point)
835
        return result
836
 
837
 
838
class gl_item_factory(object):
839
    """Factory to create objects derived from gl_item."""
840
 
841
    def create_function(self, element, context):
842
        return gl_function(element, context)
843
 
844
    def create_type(self, element, context, category):
845
        return gl_type(element, context, category)
846
 
847
    def create_enum(self, element, context, category):
848
        return gl_enum(element, context, category)
849
 
850
    def create_parameter(self, element, context):
851
        return gl_parameter(element, context)
852
 
853
    def create_api(self):
854
        return gl_api(self)
855
 
856
 
857
class gl_api(object):
858
    def __init__(self, factory):
859
        self.functions_by_name = {}
860
        self.enums_by_name = {}
861
        self.types_by_name = {}
862
 
863
        self.category_dict = {}
864
        self.categories = [{}, {}, {}, {}]
865
 
866
        self.factory = factory
867
 
868
        self.next_offset = 0
869
 
870
        typeexpr.create_initial_types()
871
        return
872
 
873
    def filter_functions(self, entry_point_list):
874
        """Filter out entry points not in entry_point_list."""
875
        functions_by_name = {}
876
        for func in self.functions_by_name.itervalues():
877
            entry_points = [ent for ent in func.entry_points if ent in entry_point_list]
878
            if entry_points:
879
                func.filter_entry_points(entry_points)
880
                functions_by_name[func.name] = func
881
 
882
        self.functions_by_name = functions_by_name
883
 
884
    def filter_functions_by_api(self, api, version = None):
885
        """Filter out entry points not in the given API (or
886
        optionally, not in the given version of the given API).
887
        """
888
        functions_by_name = {}
889
        for func in self.functions_by_name.itervalues():
890
            entry_points = func.entry_points_for_api_version(api, version)
891
            if entry_points:
892
                func.filter_entry_points(entry_points)
893
                functions_by_name[func.name] = func
894
 
895
        self.functions_by_name = functions_by_name
896
 
897
 
898
    def parse_file(self, file_name):
899
        doc = ET.parse( file_name )
900
        self.process_element(file_name, doc)
901
 
902
 
903
    def process_element(self, file_name, doc):
904
        element = doc.getroot()
905
        if element.tag == "OpenGLAPI":
906
            self.process_OpenGLAPI(file_name, element)
907
        return
908
 
909
 
910
    def process_OpenGLAPI(self, file_name, element):
911
        for child in element.getchildren():
912
            if child.tag == "category":
913
                self.process_category( child )
914
            elif child.tag == "OpenGLAPI":
915
                self.process_OpenGLAPI( file_name, child )
916
            elif child.tag == '{http://www.w3.org/2001/XInclude}include':
917
                href = child.get('href')
918
                href = os.path.join(os.path.dirname(file_name), href)
919
                self.parse_file(href)
920
 
921
        return
922
 
923
 
924
    def process_category(self, cat):
925
        cat_name = cat.get( "name" )
926
        cat_number = cat.get( "number" )
927
 
928
        [cat_type, key] = classify_category(cat_name, cat_number)
929
        self.categories[cat_type][key] = [cat_name, cat_number]
930
 
931
        for child in cat.getchildren():
932
            if child.tag == "function":
933
                func_name = real_function_name( child )
934
 
935
                temp_name = child.get( "name" )
936
                self.category_dict[ temp_name ] = [cat_name, cat_number]
937
 
938
                if self.functions_by_name.has_key( func_name ):
939
                    func = self.functions_by_name[ func_name ]
940
                    func.process_element( child )
941
                else:
942
                    func = self.factory.create_function( child, self )
943
                    self.functions_by_name[ func_name ] = func
944
 
945
                if func.offset >= self.next_offset:
946
                    self.next_offset = func.offset + 1
947
 
948
 
949
            elif child.tag == "enum":
950
                enum = self.factory.create_enum( child, self, cat_name )
951
                self.enums_by_name[ enum.name ] = enum
952
            elif child.tag == "type":
953
                t = self.factory.create_type( child, self, cat_name )
954
                self.types_by_name[ "GL" + t.name ] = t
955
 
956
        return
957
 
958
 
959
    def functionIterateByCategory(self, cat = None):
960
        """Iterate over functions by category.
961
 
962
        If cat is None, all known functions are iterated in category
963
        order.  See classify_category for details of the ordering.
964
        Within a category, functions are sorted by name.  If cat is
965
        not None, then only functions in that category are iterated.
966
        """
967
        lists = [{}, {}, {}, {}]
968
 
969
        for func in self.functionIterateAll():
970
            [cat_name, cat_number] = self.category_dict[func.name]
971
 
972
            if (cat == None) or (cat == cat_name):
973
                [func_cat_type, key] = classify_category(cat_name, cat_number)
974
 
975
                if not lists[func_cat_type].has_key(key):
976
                    lists[func_cat_type][key] = {}
977
 
978
                lists[func_cat_type][key][func.name] = func
979
 
980
 
981
        functions = []
982
        for func_cat_type in range(0,4):
983
            keys = lists[func_cat_type].keys()
984
            keys.sort()
985
 
986
            for key in keys:
987
                names = lists[func_cat_type][key].keys()
988
                names.sort()
989
 
990
                for name in names:
991
                    functions.append(lists[func_cat_type][key][name])
992
 
993
        return functions.__iter__()
994
 
995
 
996
    def functionIterateByOffset(self):
997
        max_offset = -1
998
        for func in self.functions_by_name.itervalues():
999
            if func.offset > max_offset:
1000
                max_offset = func.offset
1001
 
1002
 
1003
        temp = [None for i in range(0, max_offset + 1)]
1004
        for func in self.functions_by_name.itervalues():
1005
            if func.offset != -1:
1006
                temp[ func.offset ] = func
1007
 
1008
 
1009
        list = []
1010
        for i in range(0, max_offset + 1):
1011
            if temp[i]:
1012
                list.append(temp[i])
1013
 
1014
        return list.__iter__();
1015
 
1016
 
1017
    def functionIterateAll(self):
1018
        return self.functions_by_name.itervalues()
1019
 
1020
 
1021
    def enumIterateByName(self):
1022
        keys = self.enums_by_name.keys()
1023
        keys.sort()
1024
 
1025
        list = []
1026
        for enum in keys:
1027
            list.append( self.enums_by_name[ enum ] )
1028
 
1029
        return list.__iter__()
1030
 
1031
 
1032
    def categoryIterate(self):
1033
        """Iterate over categories.
1034
 
1035
        Iterate over all known categories in the order specified by
1036
        classify_category.  Each iterated value is a tuple of the
1037
        name and number (which may be None) of the category.
1038
        """
1039
 
1040
        list = []
1041
        for cat_type in range(0,4):
1042
            keys = self.categories[cat_type].keys()
1043
            keys.sort()
1044
 
1045
            for key in keys:
1046
                list.append(self.categories[cat_type][key])
1047
 
1048
        return list.__iter__()
1049
 
1050
 
1051
    def get_category_for_name( self, name ):
1052
        if self.category_dict.has_key(name):
1053
            return self.category_dict[name]
1054
        else:
1055
            return ["", None]
1056
 
1057
 
1058
    def typeIterate(self):
1059
        return self.types_by_name.itervalues()
1060
 
1061
 
1062
    def find_type( self, type_name ):
1063
        if type_name in self.types_by_name:
1064
            return self.types_by_name[ type_name ].type_expr
1065
        else:
1066
            print "Unable to find base type matching \"%s\"." % (type_name)
1067
            return None