made changes to support new value-mask-pad field of valueparam structures
[free-sw/xcb/proto] / xcbgen / xtypes.py
1 '''
2 This module contains the classes which represent XCB data types.
3 '''
4 from expr import Field, Expression
5 import __main__
6
7 class Type(object):
8     '''
9     Abstract base class for all XCB data types.
10     Contains default fields, and some abstract methods.
11     '''
12     def __init__(self, name):
13         '''
14         Default structure initializer.  Sets up default fields.
15
16         Public fields:
17         name is a tuple of strings specifying the full type name.
18         size is the size of the datatype in bytes, or None if variable-sized.
19         nmemb is 1 for non-list types, None for variable-sized lists, otherwise number of elts.
20         booleans for identifying subclasses, because I can't figure out isinstance().
21         '''
22         self.name = name
23         self.size = None
24         self.nmemb = None
25         self.resolved = False
26
27         # Screw isinstance().
28         self.is_simple = False
29         self.is_list = False
30         self.is_expr = False
31         self.is_container = False
32         self.is_reply = False
33         self.is_union = False
34         self.is_pad = False
35
36     def resolve(self, module):
37         '''
38         Abstract method for resolving a type.
39         This should make sure any referenced types are already declared.
40         '''
41         raise Exception('abstract resolve method not overridden!')
42
43     def out(self, name):
44         '''
45         Abstract method for outputting code.
46         These are declared in the language-specific modules, and
47         there must be a dictionary containing them declared when this module is imported!
48         '''
49         raise Exception('abstract out method not overridden!')
50
51     def fixed_size(self):
52         '''
53         Abstract method for determining if the data type is fixed-size.
54         '''
55         raise Exception('abstract fixed_size method not overridden!')
56
57     def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto):
58         '''
59         Default method for making a data type a member of a structure.
60         Extend this if the data type needs to add an additional length field or something.
61
62         module is the global module object.
63         complex_type is the structure object.
64         see Field for the meaning of the other parameters.
65         '''
66         new_field = Field(self, field_type, field_name, visible, wire, auto)
67
68         # We dump the _placeholder_byte if any fields are added.
69         for (idx, field) in enumerate(complex_type.fields):
70             if field == _placeholder_byte:
71                 complex_type.fields[idx] = new_field
72                 return
73
74         complex_type.fields.append(new_field)
75
76 class SimpleType(Type):
77     '''
78     Derived class which represents a cardinal type like CARD32 or char.
79     Any type which is typedef'ed to cardinal will be one of these.
80
81     Public fields added:
82     none
83     '''
84     def __init__(self, name, size):
85         Type.__init__(self, name)
86         self.is_simple = True
87         self.size = size
88         self.nmemb = 1
89
90     def resolve(self, module):
91         self.resolved = True
92
93     def fixed_size(self):
94         return True
95
96     out = __main__.output['simple']
97
98
99 # Cardinal datatype globals.  See module __init__ method.
100 tcard8 = SimpleType(('uint8_t',), 1)
101 tcard16 = SimpleType(('uint16_t',), 2)
102 tcard32 = SimpleType(('uint32_t',), 4)
103 tint8 =  SimpleType(('int8_t',), 1)
104 tint16 = SimpleType(('int16_t',), 2)
105 tint32 = SimpleType(('int32_t',), 4)
106 tchar =  SimpleType(('char',), 1)
107 tfloat = SimpleType(('float',), 4)
108 tdouble = SimpleType(('double',), 8)
109
110
111 class Enum(SimpleType):
112     '''
113     Derived class which represents an enum.  Fixed-size.
114
115     Public fields added:
116     values contains a list of (name, value) tuples.  value is empty, or a number.
117     '''
118     def __init__(self, name, elt):
119         SimpleType.__init__(self, name, 4)
120         self.values = []
121         for item in list(elt):
122             # First check if we're using a default value
123             if len(list(item)) == 0:
124                 self.values.append((item.get('name'), ''))
125                 continue
126
127             # An explicit value or bit was specified.
128             value = list(item)[0]
129             if value.tag == 'value':
130                 self.values.append((item.get('name'), value.text))
131             elif value.tag == 'bit':
132                 # XXX replace this with a simple number, please.
133                 self.values.append((item.get('name'), '(1 << %s)' % value.text))
134
135     def resolve(self, module):
136         self.resolved = True
137
138     def fixed_size(self):
139         return True
140
141     out = __main__.output['enum']
142
143
144 class ListType(Type):
145     '''
146     Derived class which represents a list of some other datatype.  Fixed- or variable-sized.
147
148     Public fields added:
149     member is the datatype of the list elements.
150     parent is the structure type containing the list.
151     expr is an Expression object containing the length information, for variable-sized lists.
152     '''
153     def __init__(self, elt, member, parent):
154         Type.__init__(self, member.name)
155         self.is_list = True
156         self.member = member
157         self.parent = parent
158
159         if elt.tag == 'list':
160             elts = list(elt)
161             self.expr = Expression(elts[0] if len(elts) else elt, self)
162         elif elt.tag == 'valueparam':
163             self.expr = Expression(elt, self)
164
165         self.size = member.size if member.fixed_size() else None
166         self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None
167
168     def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto):
169         if not self.fixed_size():
170             # We need a length field.
171             # Ask our Expression object for it's name, type, and whether it's on the wire.
172             lenfid = self.expr.lenfield_type
173             lenfield_name = self.expr.lenfield_name
174             lenwire = self.expr.lenwire
175             needlen = True
176
177             # See if the length field is already in the structure.
178             for field in self.parent.fields:
179                 if field.field_name == lenfield_name:
180                     needlen = False
181
182             # It isn't, so we need to add it to the structure ourself.
183             if needlen:
184                 type = module.get_type(lenfid)
185                 lenfield_type = module.get_type_name(lenfid)
186                 type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False)
187
188         # Add ourself to the structure by calling our original method.
189         Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto)
190
191     def resolve(self, module):
192         if self.resolved:
193             return
194         self.member.resolve(module)
195
196         # Find my length field again.  We need the actual Field object in the expr.
197         # This is needed because we might have added it ourself above.
198         if not self.fixed_size():
199             for field in self.parent.fields:
200                 if field.field_name == self.expr.lenfield_name and field.wire:
201                     self.expr.lenfield = field
202                     break
203             
204         self.resolved = True
205
206     def fixed_size(self):
207         return self.member.fixed_size() and self.expr.fixed_size()
208
209 class ExprType(Type):
210     '''
211     Derived class which represents an exprfield.  Fixed size.
212
213     Public fields added:
214     expr is an Expression object containing the value of the field.
215     '''
216     def __init__(self, elt, member, parent):
217         Type.__init__(self, member.name)
218         self.is_expr = True
219         self.member = member
220         self.parent = parent
221
222         self.expr = Expression(list(elt)[0], self)
223
224         self.size = member.size
225         self.nmemb = 1
226
227     def resolve(self, module):
228         if self.resolved:
229             return
230         self.member.resolve(module)
231         self.resolved = True
232
233     def fixed_size(self):
234         return True
235
236 class SizedPadType(Type):
237     '''
238     Derived class which represents a padding field of given size.
239     '''
240     def __init__(self, size):
241         Type.__init__(self, tcard8.name)
242         self.is_pad = True
243         self.size = 1
244         self.nmemb = int(size)
245
246     def resolve(self, module):
247         self.resolved = True
248
249     def fixed_size(self):
250         return True
251
252 class PadType(SizedPadType):
253     '''
254     Derived class which represents a padding field of given type.
255     '''
256     def __init__(self, elt):
257         self.nmemb = "1" if (elt == None) else elt.get('bytes')
258         SizedPadType.__init__(self, self.nmemb)
259     
260 class ComplexType(Type):
261     '''
262     Derived class which represents a structure.  Base type for all structure types.
263
264     Public fields added:
265     fields is an array of Field objects describing the structure fields.
266     '''
267     def __init__(self, name, elt):
268         Type.__init__(self, name)
269         self.is_container = True
270         self.elt = elt
271         self.fields = []
272         self.nmemb = 1
273         self.size = 0
274
275     def resolve(self, module):
276         if self.resolved:
277             return
278         pads = 0
279
280         # Resolve all of our field datatypes.
281         for child in list(self.elt):
282             value_mask_pad = None
283             if child.tag == 'pad':
284                 field_name = 'pad' + str(pads)
285                 fkey = 'CARD8'
286                 type = PadType(child)
287                 pads = pads + 1
288                 visible = False
289             elif child.tag == 'field':
290                 field_name = child.get('name')
291                 fkey = child.get('type')
292                 type = module.get_type(fkey)
293                 visible = True
294             elif child.tag == 'exprfield':
295                 field_name = child.get('name')
296                 fkey = child.get('type')
297                 type = ExprType(child, module.get_type(fkey), self)
298                 visible = False
299             elif child.tag == 'list':
300                 field_name = child.get('name')
301                 fkey = child.get('type')
302                 type = ListType(child, module.get_type(fkey), self)
303                 visible = True
304             elif child.tag == 'valueparam':
305                 field_name = child.get('value-list-name')
306                 fkey = 'CARD32'
307                 type = ListType(child, module.get_type(fkey), self)
308                 visible = True
309                 value_mask_pad = child.get('value-mask-pad')
310             else:
311                 # Hit this on Reply
312                 continue 
313
314             # Get the full type name for the field
315             field_type = module.get_type_name(fkey)
316             # Add the field to ourself
317             type.make_member_of(module, self, field_type, field_name, visible, True, False)
318             # Recursively resolve the type (could be another structure, list)
319             type.resolve(module)
320
321             # Add a value-mask-pad if necessary
322             if value_mask_pad != None:
323                 vmp_field_name = 'pad' + str(pads)
324                 vmp_fkey = 'CARD8'
325                 vmp_type = SizedPadType(value_mask_pad)
326                 pads = pads + 1
327                 vmp_visible = False
328                 vmp_field_type = module.get_type_name(vmp_fkey)
329                 vmp_type.make_member_of(module, self, vmp_field_type, vmp_field_name, vmp_visible, True, False)
330                 vmp_type.resolve(module)
331
332         self.calc_size() # Figure out how big we are
333         self.resolved = True
334
335     def calc_size(self):
336         self.size = 0
337         for m in self.fields:
338             if not m.wire:
339                 continue
340             if m.type.fixed_size():
341                 self.size = self.size + (m.type.size * m.type.nmemb)
342             else:
343                 self.size = None
344                 break
345
346     def fixed_size(self):
347         for m in self.fields:
348             if not m.type.fixed_size():
349                 return False
350         return True
351
352
353 class Struct(ComplexType):
354     '''
355     Derived class representing a struct data type.
356     '''
357     out = __main__.output['struct']
358
359
360 class Union(ComplexType):
361     '''
362     Derived class representing a union data type.
363     '''
364     def __init__(self, name, elt):
365         ComplexType.__init__(self, name, elt)
366         self.is_union = True
367
368     out = __main__.output['union']
369
370
371 class Reply(ComplexType):
372     '''
373     Derived class representing a reply.  Only found as a field of Request.
374     '''
375     def __init__(self, name, elt):
376         ComplexType.__init__(self, name, elt)
377         self.is_reply = True
378
379     def resolve(self, module):
380         if self.resolved:
381             return
382         # Add the automatic protocol fields
383         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
384         self.fields.append(_placeholder_byte)
385         self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
386         self.fields.append(Field(tcard32, tcard32.name, 'length', False, True, True))
387         ComplexType.resolve(self, module)
388         
389
390 class Request(ComplexType):
391     '''
392     Derived class representing a request.
393
394     Public fields added:
395     reply contains the reply datatype or None for void requests.
396     opcode contains the request number.
397     '''
398     def __init__(self, name, elt):
399         ComplexType.__init__(self, name, elt)
400         self.reply = None
401         self.opcode = elt.get('opcode')
402
403         for child in list(elt):
404             if child.tag == 'reply':
405                 self.reply = Reply(name, child)
406
407     def resolve(self, module):
408         if self.resolved:
409             return
410         # Add the automatic protocol fields
411         if module.namespace.is_ext:
412             self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True))
413             self.fields.append(Field(tcard8, tcard8.name, 'minor_opcode', False, True, True))
414             self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True))
415             ComplexType.resolve(self, module)
416         else:
417             self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True))
418             self.fields.append(_placeholder_byte)
419             self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True))
420             ComplexType.resolve(self, module)
421
422         if self.reply:
423             self.reply.resolve(module)
424
425     out = __main__.output['request']
426
427
428 class Event(ComplexType):
429     '''
430     Derived class representing an event data type.
431
432     Public fields added:
433     opcodes is a dictionary of name -> opcode number, for eventcopies.
434     '''
435     def __init__(self, name, elt):
436         ComplexType.__init__(self, name, elt)
437         self.opcodes = {}
438
439         tmp = elt.get('no-sequence-number')
440         self.has_seq = (tmp == None or tmp.lower() == 'false' or tmp == '0')
441             
442     def add_opcode(self, opcode, name, main):
443         self.opcodes[name] = opcode
444         if main:
445             self.name = name
446
447     def resolve(self, module):
448         if self.resolved:
449             return
450
451         # Add the automatic protocol fields
452         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
453         if self.has_seq:
454             self.fields.append(_placeholder_byte)
455             self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
456         ComplexType.resolve(self, module)
457
458     out = __main__.output['event']
459
460
461 class Error(ComplexType):
462     '''
463     Derived class representing an error data type.
464
465     Public fields added:
466     opcodes is a dictionary of name -> opcode number, for errorcopies.
467     '''
468     def __init__(self, name, elt):
469         ComplexType.__init__(self, name, elt)
470         self.opcodes = {}
471
472     def add_opcode(self, opcode, name, main):
473         self.opcodes[name] = opcode
474         if main:
475             self.name = name
476
477     def resolve(self, module):
478         if self.resolved:
479             return
480
481         # Add the automatic protocol fields
482         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
483         self.fields.append(Field(tcard8, tcard8.name, 'error_code', False, True, True))
484         self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
485         ComplexType.resolve(self, module)
486
487     out = __main__.output['error']
488
489 _placeholder_byte = Field(PadType(None), tcard8.name, 'pad0', False, True, False)