17d45beb4999a6a86c06f2af18325eb6b888880d
[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 sys, re
33
34 class glItem:
35 """Generic class on which all other API entity types are based."""
36
37 name = ""
38 category = ""
39 context = None
40 tag_name = ""
41
42 def __init__(self, tag_name, name, context):
43 self.name = name
44 self.category = context.get_category_define()
45 self.context = context
46 self.tag_name = tag_name
47
48 context.append(tag_name, self)
49 return
50
51 def startElement(self, name, attrs):
52 return
53
54 def endElement(self, name):
55 """Generic endElement handler.
56
57 Generic endElement handler. Returns 1 if the tag containing
58 the object is complete. Otherwise 0 is returned. All
59 derived class endElement handlers should call this method. If
60 the name of the ending tag is the same as the tag that
61 started this object, the object is assumed to be complete.
62
63 This fails if a tag can contain another tag with the same
64 name. The XML "<foo><foo/><bar/></foo>" would fail. The
65 object would end before the bar tag was processed."""
66
67 if name == self.tag_name:
68 return 1
69 else:
70 return 0
71 return
72
73
74 class glEnum( glItem ):
75 def __init__(self, context, name, attrs):
76 self.value = int(attrs.get('value', "0x0000"), 0)
77 self.functions = {}
78
79 enum_name = "GL_" + attrs.get('name', None)
80 glItem.__init__(self, name, enum_name, context)
81
82 def startElement(self, name, attrs):
83 if name == "size":
84 name = attrs.get('name', None)
85 count = int(attrs.get('count', "0"), 0)
86 self.functions[name] = count
87
88 return
89
90
91 class glType( glItem ):
92 def __init__(self, context, name, attrs):
93 self.size = int(attrs.get('size', "0"))
94
95 type_name = "GL" + attrs.get('name', None)
96 glItem.__init__(self, name, type_name, context)
97
98
99 class glParameter:
100 p_type = None
101 p_type_string = ""
102 p_name = None
103 p_count = 0
104 p_count_parameters = None
105 counter = None
106 is_output = 0
107 is_counter = 0
108 is_pointer = 0
109
110 def __init__(self, t, ts, n, c, p, is_output):
111 self.counter = None
112
113 try:
114 self.p_count = int(c)
115 except Exception,e:
116 self.p_count = 0
117 self.counter = c
118
119 if is_output == "true":
120 self.is_output = 1
121 else:
122 self.is_output = 0
123
124 if self.p_count > 0 or self.counter != None or p != None :
125 has_count = 1
126 else:
127 has_count = 0
128
129 self.p_type = t
130 self.p_type_string = ts
131 self.p_name = n
132 self.p_count_parameters = p
133
134 # If there is a * anywhere in the parameter's type, then it
135 # is a pointer.
136
137 if re.compile("[*]").search(ts):
138 # We could do some other validation here. For
139 # example, an output parameter should not be const,
140 # but every non-output parameter should.
141
142 self.is_pointer = 1;
143 else:
144 # If a parameter is not a pointer, then there cannot
145 # be an associated count (either fixed size or
146 # variable) and the parameter cannot be an output.
147
148 if has_count or self.is_output:
149 raise RuntimeError("Non-pointer type has count or is output.")
150 self.is_pointer = 0;
151
152 def is_variable_length_array(self):
153 return self.p_count_parameters != None
154
155 def is_array(self):
156 return self.is_pointer
157
158 def count_string(self):
159 """Return a string representing the number of items
160
161 Returns a string representing the number of items in a
162 parameter. For scalar types this will always be "1". For
163 vector types, it will depend on whether or not it is a
164 fixed length vector (like the parameter of glVertex3fv),
165 a counted length (like the vector parameter of
166 glDeleteTextures), or a general variable length vector."""
167
168 if self.is_array():
169 if self.is_variable_length_array():
170 return "compsize"
171 elif self.counter != None:
172 return self.counter
173 else:
174 return str(self.p_count)
175 else:
176 return "1"
177
178 def size(self):
179 if self.is_variable_length_array():
180 return 0
181 elif self.p_count == 0:
182 return self.p_type.size
183 else:
184 return self.p_type.size * self.p_count
185
186 class glParameterIterator:
187 def __init__(self, data):
188 self.data = data
189 self.index = 0
190
191 def next(self):
192 if self.index == len( self.data ):
193 raise StopIteration
194 i = self.index
195 self.index += 1
196 return self.data[i]
197
198 class glFunction( glItem ):
199 real_name = ""
200 fn_alias = None
201 fn_offset = -1
202 fn_return_type = "void"
203 fn_parameters = []
204
205 def __init__(self, context, name, attrs):
206 self.fn_alias = attrs.get('alias', None)
207 self.fn_parameters = []
208
209 temp = attrs.get('offset', None)
210 if temp == None or temp == "?":
211 self.fn_offset = -1
212 else:
213 self.fn_offset = int(temp)
214
215 fn_name = attrs.get('name', None)
216 if self.fn_alias != None:
217 self.real_name = self.fn_alias
218 else:
219 self.real_name = fn_name
220
221 glItem.__init__(self, name, fn_name, context)
222 return
223
224
225 def __iter__(self):
226 return glParameterIterator(self.fn_parameters)
227
228
229 def startElement(self, name, attrs):
230 if name == "param":
231 p_name = attrs.get('name', None)
232 p_type = attrs.get('type', None)
233 p_count = attrs.get('count', "0")
234 p_param = attrs.get('variable_param', None)
235 is_output = attrs.get('output', "false")
236 is_counter = attrs.get('counter', "false")
237
238 t = self.context.find_type(p_type)
239 if t == None:
240 raise RuntimeError("Unknown type '%s' in function '%s'." % (p_type, self.name))
241
242 try:
243 p = glParameter(t, p_type, p_name, p_count, p_param, is_output)
244 except RuntimeError:
245 print "Error with parameter '%s' in function '%s'." \
246 % (p_name, self.name)
247 raise
248
249 if is_counter == "true": p.is_counter = 1
250
251 self.add_parameter(p)
252 elif name == "return":
253 self.set_return_type(attrs.get('type', None))
254
255
256 def add_parameter(self, p):
257 self.fn_parameters.append(p)
258
259 def set_return_type(self, t):
260 self.fn_return_type = t
261
262 def get_parameter_string(self):
263 arg_string = ""
264 comma = ""
265 for p in self:
266 arg_string = arg_string + comma + p.p_type_string + " " + p.p_name
267 comma = ", "
268
269 if arg_string == "":
270 arg_string = "void"
271
272 return arg_string
273
274
275 class glItemFactory:
276 """Factory to create objects derived from glItem."""
277
278 def create(self, context, name, attrs):
279 if name == "function":
280 return glFunction(context, name, attrs)
281 elif name == "type":
282 return glType(context, name, attrs)
283 elif name == "enum":
284 return glEnum(context, name, attrs)
285 else:
286 return None
287
288
289 class FilterGLAPISpecBase(saxutils.XMLFilterBase):
290 name = "a"
291 license = "The license for this file is unspecified."
292 functions = {}
293 next_alias = -2
294 types = {}
295 xref = {}
296 current_object = None
297 factory = None
298 current_category = ""
299
300 def __init__(self):
301 saxutils.XMLFilterBase.__init__(self)
302 self.functions = {}
303 self.types = {}
304 self.xref = {}
305 self.factory = glItemFactory()
306
307 def find_type(self,type_name):
308 for t in self.types:
309 if re.compile(t).search(type_name):
310 return self.types[t]
311 print "Unable to find base type matching \"%s\"." % (type_name)
312 return None
313
314 def find_function(self,function_name):
315 index = self.xref[function_name]
316 return self.functions[index]
317
318 def printFunctions(self):
319 keys = self.functions.keys()
320 keys.sort()
321 prevk = -1
322 for k in keys:
323 if k < 0: continue
324
325 if self.functions[k].fn_alias == None:
326 if k != prevk + 1:
327 #print 'Missing offset %d' % (prevk)
328 pass
329 prevk = int(k)
330 self.printFunction(self.functions[k])
331
332 keys.reverse()
333 for k in keys:
334 if self.functions[k].fn_alias != None:
335 self.printFunction(self.functions[k])
336
337 return
338
339 def printHeader(self):
340 print '/* DO NOT EDIT - This file generated automatically by %s script */' \
341 % (self.name)
342 print ''
343 print '/*'
344 print ' * ' + self.license.replace('\n', '\n * ')
345 print ' */'
346 print ''
347 self.printRealHeader();
348 return
349
350 def printFooter(self):
351 self.printFunctions()
352 self.printRealFooter()
353
354
355 def get_category_define(self):
356 if re.compile("[1-9][0-9]*[.][0-9]+").match(self.current_category):
357 s = self.current_category
358 return "GL_VERSION_" + s.replace(".", "_")
359 else:
360 return self.current_category
361
362
363 def append(self, object_type, obj):
364 if object_type == "function":
365 # If the function is not an alias and has a negative
366 # offset, then we do not need to track it. These are
367 # functions that don't have an assigned offset
368
369 if obj.fn_offset >= 0 or obj.fn_alias != None:
370 if obj.fn_offset >= 0:
371 index = obj.fn_offset
372 else:
373 index = self.next_alias
374 self.next_alias -= 1
375
376 self.functions[index] = obj
377 self.xref[obj.name] = index
378 elif object_type == "type":
379 self.types[obj.name] = obj
380
381 return
382
383
384 def startElement(self, name, attrs):
385 if self.current_object != None:
386 self.current_object.startElement(name, attrs)
387 elif name == "category":
388 self.current_category = attrs.get('name', "")
389 else:
390 self.current_object = self.factory.create(self, name, attrs)
391 return
392
393 def endElement(self, name):
394 if self.current_object != None:
395 if self.current_object.endElement(name):
396 self.current_object = None
397 return
398
399 def printFunction(self,offset):
400 return
401
402 def printRealHeader(self):
403 return
404
405 def printRealFooter(self):
406 return