xcbgen-parser: support switch-case
[free-sw/xcb/proto] / xcbgen / xtypes.py
1 '''
2 This module contains the classes which represent XCB data types.
3 '''
4 from xcbgen.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         self.is_switch = False
36         self.is_case_or_bitcase = False
37         self.is_bitcase = False
38         self.is_case = False
39
40     def resolve(self, module):
41         '''
42         Abstract method for resolving a type.
43         This should make sure any referenced types are already declared.
44         '''
45         raise Exception('abstract resolve method not overridden!')
46
47     def out(self, name):
48         '''
49         Abstract method for outputting code.
50         These are declared in the language-specific modules, and
51         there must be a dictionary containing them declared when this module is imported!
52         '''
53         raise Exception('abstract out method not overridden!')
54
55     def fixed_size(self):
56         '''
57         Abstract method for determining if the data type is fixed-size.
58         '''
59         raise Exception('abstract fixed_size method not overridden!')
60
61     def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None):
62         '''
63         Default method for making a data type a member of a structure.
64         Extend this if the data type needs to add an additional length field or something.
65
66         module is the global module object.
67         complex_type is the structure object.
68         see Field for the meaning of the other parameters.
69         '''
70         new_field = Field(self, field_type, field_name, visible, wire, auto, enum)
71
72         # We dump the _placeholder_byte if any fields are added.
73         for (idx, field) in enumerate(complex_type.fields):
74             if field == _placeholder_byte:
75                 complex_type.fields[idx] = new_field
76                 return
77
78         complex_type.fields.append(new_field)
79
80     def make_fd_of(self, module, complex_type, fd_name):
81         '''
82         Method for making a fd member of a structure.
83         '''
84         new_fd = Field(self, module.get_type_name('INT32'), fd_name, True, False, False, None, True)
85         # We dump the _placeholder_byte if any fields are added.
86         for (idx, field) in enumerate(complex_type.fields):
87             if field == _placeholder_byte:
88                 complex_type.fields[idx] = new_fd
89                 return
90
91         complex_type.fields.append(new_fd)
92
93 class SimpleType(Type):
94     '''
95     Derived class which represents a cardinal type like CARD32 or char.
96     Any type which is typedef'ed to cardinal will be one of these.
97
98     Public fields added:
99     none
100     '''
101     def __init__(self, name, size):
102         Type.__init__(self, name)
103         self.is_simple = True
104         self.size = size
105         self.nmemb = 1
106
107     def resolve(self, module):
108         self.resolved = True
109
110     def fixed_size(self):
111         return True
112
113     out = __main__.output['simple']
114
115
116 # Cardinal datatype globals.  See module __init__ method.
117 tcard8 = SimpleType(('uint8_t',), 1)
118 tcard16 = SimpleType(('uint16_t',), 2)
119 tcard32 = SimpleType(('uint32_t',), 4)
120 tcard64 = SimpleType(('uint64_t',), 8)
121 tint8 =  SimpleType(('int8_t',), 1)
122 tint16 = SimpleType(('int16_t',), 2)
123 tint32 = SimpleType(('int32_t',), 4)
124 tint64 = SimpleType(('int64_t',), 8)
125 tchar =  SimpleType(('char',), 1)
126 tfloat = SimpleType(('float',), 4)
127 tdouble = SimpleType(('double',), 8)
128
129
130 class Enum(SimpleType):
131     '''
132     Derived class which represents an enum.  Fixed-size.
133
134     Public fields added:
135     values contains a list of (name, value) tuples.  value is empty, or a number.
136     bits contains a list of (name, bitnum) tuples.  items only appear if specified as a bit. bitnum is a number.
137     '''
138     def __init__(self, name, elt):
139         SimpleType.__init__(self, name, 4)
140         self.values = []
141         self.bits = []
142         self.doc = None
143         for item in list(elt):
144             if item.tag == 'doc':
145                 self.doc = Doc(name, item)
146
147             # First check if we're using a default value
148             if len(list(item)) == 0:
149                 self.values.append((item.get('name'), ''))
150                 continue
151
152             # An explicit value or bit was specified.
153             value = list(item)[0]
154             if value.tag == 'value':
155                 self.values.append((item.get('name'), value.text))
156             elif value.tag == 'bit':
157                 self.values.append((item.get('name'), '%u' % (1 << int(value.text, 0))))
158                 self.bits.append((item.get('name'), value.text))
159
160     def resolve(self, module):
161         self.resolved = True
162
163     def fixed_size(self):
164         return True
165
166     out = __main__.output['enum']
167
168
169 class ListType(Type):
170     '''
171     Derived class which represents a list of some other datatype.  Fixed- or variable-sized.
172
173     Public fields added:
174     member is the datatype of the list elements.
175     parent is the structure type containing the list.
176     expr is an Expression object containing the length information, for variable-sized lists.
177     '''
178     def __init__(self, elt, member, *parent):
179         Type.__init__(self, member.name)
180         self.is_list = True
181         self.member = member
182         self.parents = list(parent)
183
184         if elt.tag == 'list':
185             elts = list(elt)
186             self.expr = Expression(elts[0] if len(elts) else elt, self)
187         elif elt.tag == 'valueparam':
188             self.expr = Expression(elt, self)
189
190         self.size = member.size if member.fixed_size() else None
191         self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None
192
193     def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None):
194         if not self.fixed_size():
195             # We need a length field.
196             # Ask our Expression object for it's name, type, and whether it's on the wire.
197             lenfid = self.expr.lenfield_type
198             lenfield_name = self.expr.lenfield_name
199             lenwire = self.expr.lenwire
200             needlen = True
201
202             # See if the length field is already in the structure.
203             for parent in self.parents:
204                 for field in parent.fields:
205                     if field.field_name == lenfield_name:
206                         needlen = False
207
208             # It isn't, so we need to add it to the structure ourself.
209             if needlen:
210                 type = module.get_type(lenfid)
211                 lenfield_type = module.get_type_name(lenfid)
212                 type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum)
213
214         # Add ourself to the structure by calling our original method.
215         Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum)
216
217     def resolve(self, module):
218         if self.resolved:
219             return
220         self.member.resolve(module)
221         self.expr.resolve(module, self.parents)
222
223         # Find my length field again.  We need the actual Field object in the expr.
224         # This is needed because we might have added it ourself above.
225         if not self.fixed_size():
226             for parent in self.parents:
227                 for field in parent.fields:
228                     if field.field_name == self.expr.lenfield_name and field.wire:
229                         self.expr.lenfield = field
230                         break
231
232         self.resolved = True
233
234     def fixed_size(self):
235         return self.member.fixed_size() and self.expr.fixed_size()
236
237 class ExprType(Type):
238     '''
239     Derived class which represents an exprfield.  Fixed size.
240
241     Public fields added:
242     expr is an Expression object containing the value of the field.
243     '''
244     def __init__(self, elt, member, *parents):
245         Type.__init__(self, member.name)
246         self.is_expr = True
247         self.member = member
248         self.parents = parents
249
250         self.expr = Expression(list(elt)[0], self)
251
252         self.size = member.size
253         self.nmemb = 1
254
255     def resolve(self, module):
256         if self.resolved:
257             return
258         self.member.resolve(module)
259         self.resolved = True
260
261     def fixed_size(self):
262         return True
263
264 class PadType(Type):
265     '''
266     Derived class which represents a padding field.
267     '''
268     def __init__(self, elt):
269         Type.__init__(self, tcard8.name)
270         self.is_pad = True
271         self.size = 1
272         self.nmemb = 1
273         self.align = 1
274         if elt != None:
275             self.nmemb = int(elt.get('bytes', "1"), 0)
276             self.align = int(elt.get('align', "1"), 0)
277
278     def resolve(self, module):
279         self.resolved = True
280
281     def fixed_size(self):
282         return self.align <= 1
283
284     
285 class ComplexType(Type):
286     '''
287     Derived class which represents a structure.  Base type for all structure types.
288
289     Public fields added:
290     fields is an array of Field objects describing the structure fields.
291     '''
292     def __init__(self, name, elt):
293         Type.__init__(self, name)
294         self.is_container = True
295         self.elt = elt
296         self.fields = []
297         self.nmemb = 1
298         self.size = 0
299         self.lenfield_parent = [self]
300         self.fds = []
301
302     def resolve(self, module):
303         if self.resolved:
304             return
305         enum = None
306
307         # Resolve all of our field datatypes.
308         for child in list(self.elt):
309             if child.tag == 'pad':
310                 field_name = 'pad' + str(module.pads)
311                 fkey = 'CARD8'
312                 type = PadType(child)
313                 module.pads = module.pads + 1
314                 visible = False
315             elif child.tag == 'field':
316                 field_name = child.get('name')
317                 enum = child.get('enum')
318                 fkey = child.get('type')
319                 type = module.get_type(fkey)
320                 visible = True
321             elif child.tag == 'exprfield':
322                 field_name = child.get('name')
323                 fkey = child.get('type')
324                 type = ExprType(child, module.get_type(fkey), *self.lenfield_parent)
325                 visible = False
326             elif child.tag == 'list':
327                 field_name = child.get('name')
328                 fkey = child.get('type')
329                 type = ListType(child, module.get_type(fkey), *self.lenfield_parent)
330                 visible = True
331             elif child.tag == 'valueparam':
332                 field_name = child.get('value-list-name')
333                 fkey = 'CARD32'
334                 type = ListType(child, module.get_type(fkey), *self.lenfield_parent)
335                 visible = True
336             elif child.tag == 'switch':
337                 field_name = child.get('name')
338                 # construct the switch type name from the parent type and the field name
339                 field_type = self.name + (field_name,)
340                 type = SwitchType(field_type, child, *self.lenfield_parent)
341                 visible = True
342                 type.make_member_of(module, self, field_type, field_name, visible, True, False)
343                 type.resolve(module)
344                 continue
345             elif child.tag == 'fd':
346                 fd_name = child.get('name')
347                 type = module.get_type('INT32')
348                 type.make_fd_of(module, self, fd_name)
349                 continue
350             else:
351                 # Hit this on Reply
352                 continue
353
354             # Get the full type name for the field
355             field_type = module.get_type_name(fkey)
356             # Add the field to ourself
357             type.make_member_of(module, self, field_type, field_name, visible, True, False, enum)
358             # Recursively resolve the type (could be another structure, list)
359             type.resolve(module)
360
361         self.calc_size() # Figure out how big we are
362         self.resolved = True
363
364     def calc_size(self):
365         self.size = 0
366         for m in self.fields:
367             if not m.wire:
368                 continue
369             if m.type.fixed_size():
370                 self.size = self.size + (m.type.size * m.type.nmemb)
371             else:
372                 self.size = None
373                 break
374
375     def fixed_size(self):
376         for m in self.fields:
377             if not m.type.fixed_size():
378                 return False
379         return True
380
381 class SwitchType(ComplexType):
382     '''
383     Derived class which represents a List of Items.  
384
385     Public fields added:
386     bitcases is an array of Bitcase objects describing the list items
387     '''
388
389     def __init__(self, name, elt, *parents):
390         ComplexType.__init__(self, name, elt)
391         self.parents = parents
392         # FIXME: switch cannot store lenfields, so it should just delegate the parents
393         self.lenfield_parent = list(parents) + [self]
394         # self.fields contains all possible fields collected from the Bitcase objects, 
395         # whereas self.items contains the Bitcase objects themselves
396         self.bitcases = []
397
398         self.is_switch = True
399         elts = list(elt)
400         self.expr = Expression(elts[0] if len(elts) else elt, self)
401
402     def resolve(self, module):
403         if self.resolved:
404             return
405
406         parents = list(self.parents) + [self]
407
408         # Resolve all of our field datatypes.
409         for index, child in enumerate(list(self.elt)):
410             if child.tag == 'bitcase' or child.tag == 'case':
411                 field_name = child.get('name')
412                 if field_name is None:
413                     field_type = self.name + ('%s%d' % ( child.tag, index ),)
414                 else:
415                     field_type = self.name + (field_name,)
416
417                 # use self.parent to indicate anchestor, 
418                 # as switch does not contain named fields itself
419                 if child.tag == 'bitcase':
420                     type = BitcaseType(index, field_type, child, *parents)
421                 else:
422                     type = CaseType(index, field_type, child, *parents)
423
424                 # construct the switch type name from the parent type and the field name
425                 if field_name is None:
426                     type.has_name = False
427                     # Get the full type name for the field
428                     field_type = type.name               
429                 visible = True
430
431                 # add the field to ourself
432                 type.make_member_of(module, self, field_type, field_name, visible, True, False)
433
434                 # recursively resolve the type (could be another structure, list)
435                 type.resolve(module)
436                 inserted = False
437                 for new_field in type.fields:
438                     # We dump the _placeholder_byte if any fields are added.
439                     for (idx, field) in enumerate(self.fields):
440                         if field == _placeholder_byte:
441                             self.fields[idx] = new_field
442                             inserted = True
443                             break
444                     if False == inserted:
445                         self.fields.append(new_field)
446
447         self.calc_size() # Figure out how big we are
448         self.resolved = True
449
450     def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None):
451         if not self.fixed_size():
452             # We need a length field.
453             # Ask our Expression object for it's name, type, and whether it's on the wire.
454             lenfid = self.expr.lenfield_type
455             lenfield_name = self.expr.lenfield_name
456             lenwire = self.expr.lenwire
457             needlen = True
458
459             # See if the length field is already in the structure.
460             for parent in self.parents:
461                 for field in parent.fields:
462                     if field.field_name == lenfield_name:
463                         needlen = False
464
465             # It isn't, so we need to add it to the structure ourself.
466             if needlen:
467                 type = module.get_type(lenfid)
468                 lenfield_type = module.get_type_name(lenfid)
469                 type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum)
470
471         # Add ourself to the structure by calling our original method.
472         Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum)
473
474     # size for switch can only be calculated at runtime
475     def calc_size(self):
476         pass
477
478     # note: switch is _always_ of variable size, but we indicate here wether 
479     # it contains elements that are variable-sized themselves
480     def fixed_size(self):
481         return False
482 #        for m in self.fields:
483 #            if not m.type.fixed_size():
484 #                return False
485 #        return True
486
487
488 class Struct(ComplexType):
489     '''
490     Derived class representing a struct data type.
491     '''
492     out = __main__.output['struct']
493
494
495 class Union(ComplexType):
496     '''
497     Derived class representing a union data type.
498     '''
499     def __init__(self, name, elt):
500         ComplexType.__init__(self, name, elt)
501         self.is_union = True
502
503     out = __main__.output['union']
504
505
506 class CaseOrBitcaseType(ComplexType):
507     '''
508     Derived class representing a case or bitcase.
509     '''
510     def __init__(self, index, name, elt, *parent):
511         elts = list(elt)
512         self.expr = []
513         fields = []
514         for elt in elts:
515             if elt.tag == 'enumref':
516                 self.expr.append(Expression(elt, self))
517             else:
518                 fields.append(elt)
519         ComplexType.__init__(self, name, fields)
520         self.has_name = True
521         self.index = 1
522         self.lenfield_parent = list(parent) + [self]
523         self.parents = list(parent)
524         self.is_case_or_bitcase = True
525
526     def make_member_of(self, module, switch_type, field_type, field_name, visible, wire, auto, enum=None):
527         '''
528         register BitcaseType with the corresponding SwitchType
529
530         module is the global module object.
531         complex_type is the structure object.
532         see Field for the meaning of the other parameters.
533         '''
534         new_field = Field(self, field_type, field_name, visible, wire, auto, enum)
535
536         # We dump the _placeholder_byte if any bitcases are added.
537         for (idx, field) in enumerate(switch_type.bitcases):
538             if field == _placeholder_byte:
539                 switch_type.bitcases[idx] = new_field
540                 return
541
542         switch_type.bitcases.append(new_field)
543
544     def resolve(self, module):
545         if self.resolved:
546             return
547
548         for e in self.expr:
549             e.resolve(module, self.parents+[self])
550
551         # Resolve the bitcase expression
552         ComplexType.resolve(self, module)
553
554
555 class BitcaseType(CaseOrBitcaseType):
556     '''
557     Derived class representing a bitcase.
558     '''
559     def __init__(self, index, name, elt, *parent):
560         CaseOrBitcaseType.__init__(self, index, name, elt, *parent)
561         self.is_bitcase = True
562
563 class CaseType(CaseOrBitcaseType):
564     '''
565     Derived class representing a case.
566     '''
567     def __init__(self, index, name, elt, *parent):
568         CaseOrBitcaseType.__init__(self, index, name, elt, *parent)
569         self.is_case = True
570
571
572 class Reply(ComplexType):
573     '''
574     Derived class representing a reply.  Only found as a field of Request.
575     '''
576     def __init__(self, name, elt):
577         ComplexType.__init__(self, name, elt)
578         self.is_reply = True
579         self.doc = None
580
581         for child in list(elt):
582             if child.tag == 'doc':
583                 self.doc = Doc(name, child)
584
585     def resolve(self, module):
586         if self.resolved:
587             return
588         # Reset pads count
589         module.pads = 0
590         # Add the automatic protocol fields
591         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
592         self.fields.append(_placeholder_byte)
593         self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
594         self.fields.append(Field(tcard32, tcard32.name, 'length', False, True, True))
595         ComplexType.resolve(self, module)
596         
597
598 class Request(ComplexType):
599     '''
600     Derived class representing a request.
601
602     Public fields added:
603     reply contains the reply datatype or None for void requests.
604     opcode contains the request number.
605     '''
606     def __init__(self, name, elt):
607         ComplexType.__init__(self, name, elt)
608         self.reply = None
609         self.doc = None
610         self.opcode = elt.get('opcode')
611
612         for child in list(elt):
613             if child.tag == 'reply':
614                 self.reply = Reply(name, child)
615             if child.tag == 'doc':
616                 self.doc = Doc(name, child)
617
618     def resolve(self, module):
619         if self.resolved:
620             return
621         # Add the automatic protocol fields
622         if module.namespace.is_ext:
623             self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True))
624             self.fields.append(Field(tcard8, tcard8.name, 'minor_opcode', False, True, True))
625             self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True))
626             ComplexType.resolve(self, module)
627         else:
628             self.fields.append(Field(tcard8, tcard8.name, 'major_opcode', False, True, True))
629             self.fields.append(_placeholder_byte)
630             self.fields.append(Field(tcard16, tcard16.name, 'length', False, True, True))
631             ComplexType.resolve(self, module)
632
633         if self.reply:
634             self.reply.resolve(module)
635
636     out = __main__.output['request']
637
638
639 class Event(ComplexType):
640     '''
641     Derived class representing an event data type.
642
643     Public fields added:
644     opcodes is a dictionary of name -> opcode number, for eventcopies.
645     '''
646     def __init__(self, name, elt):
647         ComplexType.__init__(self, name, elt)
648         self.opcodes = {}
649
650         self.has_seq = not bool(elt.get('no-sequence-number'))
651
652         self.is_ge_event = bool(elt.get('xge'))
653
654         self.doc = None
655         for item in list(elt):
656             if item.tag == 'doc':
657                 self.doc = Doc(name, item)
658
659     def add_opcode(self, opcode, name, main):
660         self.opcodes[name] = opcode
661         if main:
662             self.name = name
663
664     def resolve(self, module):
665         def add_event_header():
666             self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
667             if self.has_seq:
668                 self.fields.append(_placeholder_byte)
669                 self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
670
671         def add_ge_event_header():
672             self.fields.append(Field(tcard8,  tcard8.name,  'response_type', False, True, True))
673             self.fields.append(Field(tcard8,  tcard8.name,  'extension', False, True, True))
674             self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
675             self.fields.append(Field(tcard32, tcard32.name, 'length', False, True, True))
676             self.fields.append(Field(tcard16, tcard16.name, 'event_type', False, True, True))
677
678         if self.resolved:
679             return
680
681         # Add the automatic protocol fields
682         if self.is_ge_event:
683             add_ge_event_header()
684         else:
685             add_event_header()
686
687         ComplexType.resolve(self, module)
688
689     out = __main__.output['event']
690
691
692 class Error(ComplexType):
693     '''
694     Derived class representing an error data type.
695
696     Public fields added:
697     opcodes is a dictionary of name -> opcode number, for errorcopies.
698     '''
699     def __init__(self, name, elt):
700         ComplexType.__init__(self, name, elt)
701         self.opcodes = {}
702
703     def add_opcode(self, opcode, name, main):
704         self.opcodes[name] = opcode
705         if main:
706             self.name = name
707
708     def resolve(self, module):
709         if self.resolved:
710             return
711
712         # Add the automatic protocol fields
713         self.fields.append(Field(tcard8, tcard8.name, 'response_type', False, True, True))
714         self.fields.append(Field(tcard8, tcard8.name, 'error_code', False, True, True))
715         self.fields.append(Field(tcard16, tcard16.name, 'sequence', False, True, True))
716         ComplexType.resolve(self, module)
717
718     out = __main__.output['error']
719
720
721 class Doc(object):
722     '''
723     Class representing a <doc> tag.
724     '''
725     def __init__(self, name, elt):
726         self.name = name
727         self.description = None
728         self.brief = 'BRIEF DESCRIPTION MISSING'
729         self.fields = {}
730         self.errors = {}
731         self.see = {}
732         self.example = None
733
734         for child in list(elt):
735             text = child.text if child.text else ''
736             if child.tag == 'description':
737                 self.description = text.strip()
738             if child.tag == 'brief':
739                 self.brief = text.strip()
740             if child.tag == 'field':
741                 self.fields[child.get('name')] = text.strip()
742             if child.tag == 'error':
743                 self.errors[child.get('type')] = text.strip()
744             if child.tag == 'see':
745                 self.see[child.get('name')] = child.get('type')
746             if child.tag == 'example':
747                 self.example = text.strip()
748
749
750
751 _placeholder_byte = Field(PadType(None), tcard8.name, 'pad0', False, True, False)