xcbgen: perform lenfield lookup within all anchestors
[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     bits contains a list of (name, bitnum) tuples.  items only appear if specified as a bit. bitnum is a number.
118     '''
119     def __init__(self, name, elt):
120         SimpleType.__init__(self, name, 4)
121         self.values = []
122         self.bits = []
123         for item in list(elt):
124             # First check if we're using a default value
125             if len(list(item)) == 0:
126                 self.values.append((item.get('name'), ''))
127                 continue
128
129             # An explicit value or bit was specified.
130             value = list(item)[0]
131             if value.tag == 'value':
132                 self.values.append((item.get('name'), value.text))
133             elif value.tag == 'bit':
134                 self.values.append((item.get('name'), '%u' % (1 << int(value.text, 0))))
135                 self.bits.append((item.get('name'), value.text))
136
137     def resolve(self, module):
138         self.resolved = True
139
140     def fixed_size(self):
141         return True
142
143     out = __main__.output['enum']
144
145
146 class ListType(Type):
147     '''
148     Derived class which represents a list of some other datatype.  Fixed- or variable-sized.
149
150     Public fields added:
151     member is the datatype of the list elements.
152     parent is the structure type containing the list.
153     expr is an Expression object containing the length information, for variable-sized lists.
154     '''
155     def __init__(self, elt, member, *parent):
156         Type.__init__(self, member.name)
157         self.is_list = True
158         self.member = member
159         self.parent = parent
160
161         if elt.tag == 'list':
162             elts = list(elt)
163             self.expr = Expression(elts[0] if len(elts) else elt, self)
164         elif elt.tag == 'valueparam':
165             self.expr = Expression(elt, self)
166
167         self.size = member.size if member.fixed_size() else None
168         self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None
169
170     def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto):
171         if not self.fixed_size():
172             # We need a length field.
173             # Ask our Expression object for it's name, type, and whether it's on the wire.
174             lenfid = self.expr.lenfield_type
175             lenfield_name = self.expr.lenfield_name
176             lenwire = self.expr.lenwire
177             needlen = True
178
179             # See if the length field is already in the structure.
180             for parent in self.parent:
181                 for field in parent.fields:
182                     if field.field_name == lenfield_name:
183                         needlen = False
184
185             # It isn't, so we need to add it to the structure ourself.
186             if needlen:
187                 type = module.get_type(lenfid)
188                 lenfield_type = module.get_type_name(lenfid)
189                 type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False)
190
191         # Add ourself to the structure by calling our original method.
192         Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto)
193
194     def resolve(self, module):
195         if self.resolved:
196             return
197         self.member.resolve(module)
198
199         # Find my length field again.  We need the actual Field object in the expr.
200         # This is needed because we might have added it ourself above.
201         if not self.fixed_size():
202             for parent in self.parent:
203                 for field in parent.fields:
204                     if field.field_name == self.expr.lenfield_name and field.wire:
205                         self.expr.lenfield = field
206                         break
207             
208         self.resolved = True
209
210     def fixed_size(self):
211         return self.member.fixed_size() and self.expr.fixed_size()
212
213 class ExprType(Type):
214     '''
215     Derived class which represents an exprfield.  Fixed size.
216
217     Public fields added:
218     expr is an Expression object containing the value of the field.
219     '''
220     def __init__(self, elt, member, *parent):
221         Type.__init__(self, member.name)
222         self.is_expr = True
223         self.member = member
224         self.parent = parent
225
226         self.expr = Expression(list(elt)[0], self)
227
228         self.size = member.size
229         self.nmemb = 1
230
231     def resolve(self, module):
232         if self.resolved:
233             return
234         self.member.resolve(module)
235         self.resolved = True
236
237     def fixed_size(self):
238         return True
239
240 class PadType(Type):
241     '''
242     Derived class which represents a padding field.
243     '''
244     def __init__(self, elt):
245         Type.__init__(self, tcard8.name)
246         self.is_pad = True
247         self.size = 1
248         self.nmemb = 1 if (elt == None) else int(elt.get('bytes'), 0)
249
250     def resolve(self, module):
251         self.resolved = True
252
253     def fixed_size(self):
254         return True
255
256     
257 class ComplexType(Type):
258     '''
259     Derived class which represents a structure.  Base type for all structure types.
260
261     Public fields added:
262     fields is an array of Field objects describing the structure fields.
263     '''
264     def __init__(self, name, elt):
265         Type.__init__(self, name)
266         self.is_container = True
267         self.elt = elt
268         self.fields = []
269         self.nmemb = 1
270         self.size = 0
271         self.lenfield_parent = [self]
272
273     def resolve(self, module):
274         if self.resolved:
275             return
276         pads = 0
277
278         # Resolve all of our field datatypes.
279         for child in list(self.elt):
280             if child.tag == 'pad':
281                 field_name = 'pad' + str(pads)
282                 fkey = 'CARD8'
283                 type = PadType(child)
284                 pads = pads + 1
285                 visible = False
286             elif child.tag == 'field':
287                 field_name = child.get('name')
288                 fkey = child.get('type')
289                 type = module.get_type(fkey)
290                 visible = True
291             elif child.tag == 'exprfield':
292                 field_name = child.get('name')
293                 fkey = child.get('type')
294                 type = ExprType(child, module.get_type(fkey), *self.lenfield_parent)
295                 visible = False
296             elif child.tag == 'list':
297                 field_name = child.get('name')
298                 fkey = child.get('type')
299                 type = ListType(child, module.get_type(fkey), *self.lenfield_parent)
300                 visible = True
301             elif child.tag == 'valueparam':
302                 field_name = child.get('value-list-name')
303                 fkey = 'CARD32'
304                 type = ListType(child, module.get_type(fkey), *self.lenfield_parent)
305                 visible = True
306             else:
307                 # Hit this on Reply
308                 continue 
309
310             # Get the full type name for the field
311             field_type = module.get_type_name(fkey)
312             # Add the field to ourself
313             type.make_member_of(module, self, field_type, field_name, visible, True, False)
314             # Recursively resolve the type (could be another structure, list)
315             type.resolve(module)
316
317         self.calc_size() # Figure out how big we are
318         self.resolved = True
319
320     def calc_size(self):
321         self.size = 0
322         for m in self.fields:
323             if not m.wire:
324                 continue
325             if m.type.fixed_size():
326                 self.size = self.size + (m.type.size * m.type.nmemb)
327             else:
328                 self.size = None
329                 break
330
331     def fixed_size(self):
332         for m in self.fields:
333             if not m.type.fixed_size():
334                 return False
335         return True
336
337
338 class Struct(ComplexType):
339     '''
340     Derived class representing a struct data type.
341     '''
342     out = __main__.output['struct']
343
344
345 class Union(ComplexType):
346     '''
347     Derived class representing a union data type.
348     '''
349     def __init__(self, name, elt):
350         ComplexType.__init__(self, name, elt)
351         self.is_union = True
352
353     out = __main__.output['union']
354
355
356 class Reply(ComplexType):
357     '''
358     Derived class representing a reply.  Only found as a field of Request.
359     '''
360     def __init__(self, name, elt):
361         ComplexType.__init__(self, name, elt)
362         self.is_reply = True
363
364     def resolve(self, module):
365         if self.resolved:
366             return
367         # Add the automatic protocol fields
368         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
369         self.fields.append(_placeholder_byte)
370         self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
371         self.fields.append(Field(tcard32, tcard32.name, 'length', False, True, True))
372         ComplexType.resolve(self, module)
373         
374
375 class Request(ComplexType):
376     '''
377     Derived class representing a request.
378
379     Public fields added:
380     reply contains the reply datatype or None for void requests.
381     opcode contains the request number.
382     '''
383     def __init__(self, name, elt):
384         ComplexType.__init__(self, name, elt)
385         self.reply = None
386         self.opcode = elt.get('opcode')
387
388         for child in list(elt):
389             if child.tag == 'reply':
390                 self.reply = Reply(name, child)
391
392     def resolve(self, module):
393         if self.resolved:
394             return
395         # Add the automatic protocol fields
396         if module.namespace.is_ext:
397             self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True))
398             self.fields.append(Field(tcard8, tcard8.name, 'minor_opcode', False, True, True))
399             self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True))
400             ComplexType.resolve(self, module)
401         else:
402             self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True))
403             self.fields.append(_placeholder_byte)
404             self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True))
405             ComplexType.resolve(self, module)
406
407         if self.reply:
408             self.reply.resolve(module)
409
410     out = __main__.output['request']
411
412
413 class Event(ComplexType):
414     '''
415     Derived class representing an event data type.
416
417     Public fields added:
418     opcodes is a dictionary of name -> opcode number, for eventcopies.
419     '''
420     def __init__(self, name, elt):
421         ComplexType.__init__(self, name, elt)
422         self.opcodes = {}
423
424         tmp = elt.get('no-sequence-number')
425         self.has_seq = (tmp == None or tmp.lower() == 'false' or tmp == '0')
426             
427     def add_opcode(self, opcode, name, main):
428         self.opcodes[name] = opcode
429         if main:
430             self.name = name
431
432     def resolve(self, module):
433         if self.resolved:
434             return
435
436         # Add the automatic protocol fields
437         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
438         if self.has_seq:
439             self.fields.append(_placeholder_byte)
440             self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
441         ComplexType.resolve(self, module)
442
443     out = __main__.output['event']
444
445
446 class Error(ComplexType):
447     '''
448     Derived class representing an error data type.
449
450     Public fields added:
451     opcodes is a dictionary of name -> opcode number, for errorcopies.
452     '''
453     def __init__(self, name, elt):
454         ComplexType.__init__(self, name, elt)
455         self.opcodes = {}
456
457     def add_opcode(self, opcode, name, main):
458         self.opcodes[name] = opcode
459         if main:
460             self.name = name
461
462     def resolve(self, module):
463         if self.resolved:
464             return
465
466         # Add the automatic protocol fields
467         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
468         self.fields.append(Field(tcard8, tcard8.name, 'error_code', False, True, True))
469         self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
470         ComplexType.resolve(self, module)
471
472     out = __main__.output['error']
473
474 _placeholder_byte = Field(PadType(None), tcard8.name, 'pad0', False, True, False)