55bbddafa5b8f592e53dda22e6fbbdff9ceb8d6b
[profile/ivi/mesa.git] / src / mesa / glapi / gl_XML.py
1 #!/usr/bin/python2
2
3 # (C) Copyright IBM Corporation 2004
4 # All Rights Reserved.
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a
7 # copy of this software and associated documentation files (the "Software"),
8 # to deal in the Software without restriction, including without limitation
9 # on the rights to use, copy, modify, merge, publish, distribute, sub
10 # license, and/or sell copies of the Software, and to permit persons to whom
11 # the Software is furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice (including the next
14 # paragraph) shall be included in all copies or substantial portions of the
15 # Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
20 # IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23 # IN THE SOFTWARE.
24 #
25 # Authors:
26 #    Ian Romanick <idr@us.ibm.com>
27
28 from xml.sax import saxutils
29 from xml.sax import make_parser
30 from xml.sax.handler import feature_namespaces
31
32 import re
33
34 class glItem:
35         """Generic class on which all other API entity types are based."""
36
37         def __init__(self, tag_name, name, context):
38                 self.name = name
39                 self.category = context.get_category_define()
40                 self.context = context
41                 self.tag_name = tag_name
42                 
43                 context.append(tag_name, self)
44                 return
45         
46         def startElement(self, name, attrs):
47                 """Generic startElement handler.
48                 
49                 The startElement handler is called for all elements except
50                 the one that starts the object.  For a foo element, the
51                 XML "<foo><bar/></foo>" would cause the startElement handler
52                 to be called once, but the endElement handler would be called
53                 twice."""
54                 return
55
56         def endElement(self, name):
57                 """Generic endElement handler.
58
59                 Generic endElement handler.    Returns 1 if the tag containing
60                 the object is complete.  Otherwise 0 is returned.  All
61                 derived class endElement handlers should call this method.  If
62                 the name of the ending tag is the same as the tag that
63                 started this object, the object is assumed to be complete.
64                 
65                 This fails if a tag can contain another tag with the same
66                 name.  The XML "<foo><foo/><bar/></foo>" would fail.  The
67                 object would end before the bar tag was processed.
68                 
69                 The endElement handler is called for every end element
70                 associated with an object, even the element that started the
71                 object.  See the description of startElement an example."""
72
73                 if name == self.tag_name:
74                         return 1
75                 else:
76                         return 0
77
78         def get_category_define(self):
79                 return self.category
80
81
82 class glEnum( glItem ):
83         """Subclass of glItem for representing GL enumerants.
84         
85         This class is not complete, and is not really used yet."""
86
87         def __init__(self, context, name, attrs):
88                 self.value = int(attrs.get('value', "0x0000"), 0)
89                 self.functions = {}
90
91                 enum_name = "GL_" + attrs.get('name', None)
92                 glItem.__init__(self, name, enum_name, context)
93
94         def startElement(self, name, attrs):
95                 if name == "size":
96                         name = attrs.get('name', None)
97                         count = int(attrs.get('count', "0"), 0)
98                         self.functions[name] = count
99
100                 return
101
102
103 class glType( glItem ):
104         """Subclass of glItem for representing GL types."""
105
106         def __init__(self, context, name, attrs):
107                 self.size = int(attrs.get('size', "0"))
108
109                 type_name = "GL" + attrs.get('name', None)
110                 glItem.__init__(self, name, type_name, context)
111
112
113 class glParameter( glItem ):
114         """Parameter of a glFunction."""
115         p_type = None
116         p_type_string = ""
117         p_count = 0
118         p_count_parameters = None
119         counter = None
120         is_output = 0
121         is_counter = 0
122         is_pointer = 0
123
124         def __init__(self, context, name, attrs):
125                 p_name = attrs.get('name', None)
126                 self.p_type_string = attrs.get('type', None)
127                 self.p_count_parameters = attrs.get('variable_param', None)
128
129                 self.p_type = context.context.find_type(self.p_type_string)
130                 if self.p_type == None:
131                         raise RuntimeError("Unknown type '%s' in function '%s'." % (self.p_type_string, context.name))
132
133
134                 # The count tag can be either a numeric string or the name of
135                 # a variable.  If it is the name of a variable, the int(c)
136                 # statement will throw an exception, and the except block will
137                 # take over.
138
139                 c = attrs.get('count', "0")
140                 try: 
141                         self.p_count = int(c)
142                         self.counter = None
143                 except Exception,e:
144                         self.p_count = 0
145                         self.counter = c
146
147                 if attrs.get('counter', "false") == "true":
148                         self.is_counter = 1
149                 else:
150                         self.is_counter = 0
151
152                 if attrs.get('output', "false") == "true":
153                         self.is_output = 1
154                 else:
155                         self.is_output = 0
156
157                 if self.p_count > 0 or self.counter != None or self.p_count_parameters != None :
158                         has_count = 1
159                 else:
160                         has_count = 0
161
162
163                 # If there is a * anywhere in the parameter's type, then it
164                 # is a pointer.
165
166                 if re.compile("[*]").search(self.p_type_string):
167                         # We could do some other validation here.  For
168                         # example, an output parameter should not be const,
169                         # but every non-output parameter should.
170
171                         self.is_pointer = 1;
172                 else:
173                         # If a parameter is not a pointer, then there cannot
174                         # be an associated count (either fixed size or
175                         # variable) and the parameter cannot be an output.
176
177                         if has_count or self.is_output:
178                                 raise RuntimeError("Non-pointer type has count or is output.")
179                         self.is_pointer = 0;
180
181                 glItem.__init__(self, name, p_name, context)
182                 return
183
184
185         def is_variable_length_array(self):
186                 """Determine if a parameter is a variable length array.
187                 
188                 A parameter is considered to be a variable length array if
189                 its size depends on the value of another parameter that is
190                 an enumerant.  The params parameter to glTexEnviv is an
191                 example of a variable length array parameter.  Arrays whose
192                 size depends on a count variable, such as the lists parameter
193                 to glCallLists, are not variable length arrays in this
194                 sense."""
195
196                 return self.p_count_parameters != None
197
198
199         def is_array(self):
200                 return self.is_pointer
201
202
203         def count_string(self):
204                 """Return a string representing the number of items
205                 
206                 Returns a string representing the number of items in a
207                 parameter.  For scalar types this will always be "1".  For
208                 vector types, it will depend on whether or not it is a
209                 fixed length vector (like the parameter of glVertex3fv),
210                 a counted length (like the vector parameter of
211                 glDeleteTextures), or a general variable length vector."""
212
213                 if self.is_array():
214                         if self.is_variable_length_array():
215                                 return "compsize"
216                         elif self.counter != None:
217                                 return self.counter
218                         else:
219                                 return str(self.p_count)
220                 else:
221                         return "1"
222
223
224         def size(self):
225                 if self.is_variable_length_array():
226                         return 0
227                 elif self.p_count == 0:
228                         return self.p_type.size
229                 else:
230                         return self.p_type.size * self.p_count
231
232
233 class glParameterIterator:
234         """Class to iterate over a list of glParameters.
235         
236         Objects of this class are returned by the __iter__ method of the
237         glFunction class.  They are used to iterate over the list of
238         parameters to the function."""
239
240         def __init__(self, data):
241                 self.data = data
242                 self.index = 0
243                 
244         def next(self):
245                 if self.index == len( self.data ):
246                         raise StopIteration
247                 i = self.index
248                 self.index += 1
249                 return self.data[i]
250
251
252 class glFunction( glItem ):
253         real_name = ""
254         fn_alias = None
255         fn_offset = -1
256         fn_return_type = "void"
257         fn_parameters = []
258
259         def __init__(self, context, name, attrs):
260                 self.fn_alias = attrs.get('alias', None)
261                 self.fn_parameters = []
262
263                 temp = attrs.get('offset', None)
264                 if temp == None or temp == "?":
265                         self.fn_offset = -1
266                 else:
267                         self.fn_offset = int(temp)
268
269                 fn_name = attrs.get('name', None)
270                 if self.fn_alias != None:
271                         self.real_name = self.fn_alias
272                 else:
273                         self.real_name = fn_name
274
275                 glItem.__init__(self, name, fn_name, context)
276                 return
277
278
279         def __iter__(self):
280                 return glParameterIterator(self.fn_parameters)
281
282
283         def startElement(self, name, attrs):
284                 if name == "param":
285                         try:
286                                 glParameter(self, name, attrs)
287                         except RuntimeError:
288                                 print "Error with parameter '%s' in function '%s'." \
289                                         % (attrs.get('name','(unknown)'), self.name)
290                                 raise
291                 elif name == "return":
292                         self.set_return_type(attrs.get('type', None))
293
294
295         def append(self, tag_name, p):
296                 if tag_name != "param":
297                         raise RuntimeError("Trying to append '%s' to parameter list of function '%s'." % (tag_name, self.name))
298
299                 self.fn_parameters.append(p)
300
301
302         def set_return_type(self, t):
303                 self.fn_return_type = t
304
305
306         def get_parameter_string(self):
307                 arg_string = ""
308                 comma = ""
309                 for p in self:
310                         arg_string = arg_string + comma + p.p_type_string + " " + p.name
311                         comma = ", "
312
313                 if arg_string == "":
314                         arg_string = "void"
315
316                 return arg_string
317
318
319 class glItemFactory:
320         """Factory to create objects derived from glItem."""
321     
322         def create(self, context, name, attrs):
323                 if name == "function":
324                         return glFunction(context, name, attrs)
325                 elif name == "type":
326                         return glType(context, name, attrs)
327                 elif name == "enum":
328                         return glEnum(context, name, attrs)
329                 else:
330                         return None
331
332
333 class FilterGLAPISpecBase(saxutils.XMLFilterBase):
334         name = "a"
335         license = "The license for this file is unspecified."
336         functions = {}
337         next_alias = -2
338         types = {}
339         xref = {}
340         current_object = None
341         factory = None
342         current_category = ""
343
344         def __init__(self):
345                 saxutils.XMLFilterBase.__init__(self)
346                 self.functions = {}
347                 self.types = {}
348                 self.xref = {}
349                 self.factory = glItemFactory()
350
351
352         def find_type(self,type_name):
353                 for t in self.types:
354                         if re.compile(t).search(type_name):
355                                 return self.types[t]
356                 print "Unable to find base type matching \"%s\"." % (type_name)
357                 return None
358
359
360         def find_function(self,function_name):
361                 index = self.xref[function_name]
362                 return self.functions[index]
363
364
365         def printFunctions(self):
366                 keys = self.functions.keys()
367                 keys.sort()
368                 prevk = -1
369                 for k in keys:
370                         if k < 0: continue
371
372                         if self.functions[k].fn_alias == None:
373                                 if k != prevk + 1:
374                                         #print 'Missing offset %d' % (prevk)
375                                         pass
376                         prevk = int(k)
377                         self.printFunction(self.functions[k])
378
379                 keys.reverse()
380                 for k in keys:
381                         if self.functions[k].fn_alias != None:
382                                 self.printFunction(self.functions[k])
383
384                 return
385
386
387         def printHeader(self):
388                 """Print the header associated with all files and call the printRealHeader method."""
389
390                 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
391                         % (self.name)
392                 print ''
393                 print '/*'
394                 print ' * ' + self.license.replace('\n', '\n * ')
395                 print ' */'
396                 print ''
397                 self.printRealHeader();
398                 return
399
400
401         def printFooter(self):
402                 """Print the header associated with all files and call the printRealFooter method."""
403
404                 self.printFunctions()
405                 self.printRealFooter()
406
407
408         def get_category_define(self):
409                 """Convert the category name to the #define that would be found in glext.h"""
410
411                 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
412                         s = self.current_category
413                         return "GL_VERSION_" + s.replace(".", "_")
414                 else:
415                         return self.current_category
416
417
418         def append(self, object_type, obj):
419                 if object_type == "function":
420                         # If the function is not an alias and has a negative
421                         # offset, then we do not need to track it.  These are
422                         # functions that don't have an assigned offset
423
424                         if obj.fn_offset >= 0 or obj.fn_alias != None:
425                                 if obj.fn_offset >= 0:
426                                         index = obj.fn_offset
427                                 else:
428                                         index = self.next_alias
429                                         self.next_alias -= 1
430
431                                 self.functions[index] = obj
432                                 self.xref[obj.name] = index
433                 elif object_type == "type":
434                         self.types[obj.name] = obj
435
436                 return
437
438
439         def startElement(self, name, attrs):
440                 """Start a new element in the XML stream.
441                 
442                 Starts a new element.  There are three types of elements that
443                 are specially handled by this function.  When a "category"
444                 element is encountered, the name of the category is saved.
445                 If an element is encountered and no API object is
446                 in-progress, a new object is created using the API factory.
447                 Any future elements, until that API object is closed, are
448                 passed to the current objects startElement method.
449         
450                 This paradigm was chosen becuase it allows subclasses of the
451                 basic API types (i.e., glFunction, glEnum, etc.) to handle
452                 additional XML data, GLX protocol information,  that the base
453                 classes do not know about."""
454
455                 if self.current_object != None:
456                         self.current_object.startElement(name, attrs)
457                 elif name == "category":
458                         self.current_category = attrs.get('name', "")
459                 else:
460                         self.current_object = self.factory.create(self, name, attrs)
461                 return
462
463
464         def endElement(self, name):
465                 if self.current_object != None:
466                         if self.current_object.endElement(name):
467                                 self.current_object = None
468                 return
469
470
471         def printFunction(self,offset):
472                 """Print a single function.
473
474                 In the base class, this function is empty.  All derived
475                 classes should over-ride this function."""
476                 return
477     
478
479         def printRealHeader(self):
480                 """Print the "real" header for the created file.
481
482                 In the base class, this function is empty.  All derived
483                 classes should over-ride this function."""
484                 return
485
486
487         def printRealFooter(self):
488                 """Print the "real" footer for the created file.
489
490                 In the base class, this function is empty.  All derived
491                 classes should over-ride this function."""
492                 return