xcbgen: Remove tab from xtypes.py.
[free-sw/xcb/proto] / xcbgen / expr.py
1 '''
2 This module contains helper classes for structure fields and length expressions.
3 '''
4 class Field(object):
5     '''
6     Represents a field of a structure.
7
8     type is the datatype object for the field.
9     field_type is the name of the type (string tuple)
10     field_name is the name of the structure field.
11     visible is true iff the field should be in the request API.
12     wire is true iff the field should be in the request structure.
13     auto is true iff the field is on the wire but not in the request API (e.g. opcode)
14     enum is the enum name this field refers to, if any.
15     '''
16     def __init__(self, type, field_type, field_name, visible, wire, auto, enum=None, isfd=False):
17         self.type = type
18         self.field_type = field_type
19         self.field_name = field_name
20         self.enum = enum
21         self.visible = visible
22         self.wire = wire
23         self.auto = auto
24         self.isfd = isfd
25
26
27 class Expression(object):
28     '''
29     Represents a mathematical expression for a list length or exprfield.
30
31     Public fields:
32     op is the operation (text +,*,/,<<,~) or None.
33     lhs and rhs are the sub-Expressions if op is set.
34     lenfield_name is the name of the length field, or None for request lists.
35     lenfield is the Field object for the length field, or None.
36     bitfield is True if the length field is a bitmask instead of a number.
37     nmemb is the fixed size (value)of the expression, or None
38     '''
39     def __init__(self, elt, parent):
40         self.parent = parent
41
42         self.nmemb = None
43
44         self.lenfield_name = None
45         self.lenfield_type = None
46         self.lenfield_parent = None
47         self.lenfield = None
48         self.lenwire = False
49         self.bitfield = False
50
51         self.op = None
52         self.lhs = None
53         self.rhs = None
54
55         if elt.tag == 'list':
56             # List going into a request, which has no length field (inferred by server)
57             self.lenfield_name = elt.get('name') + '_len'
58             self.lenfield_type = 'CARD32'
59
60         elif elt.tag == 'fieldref':
61             # Standard list with a fieldref
62             self.lenfield_name = elt.text
63
64         elif elt.tag == 'valueparam':
65             # Value-mask.  The length bitmask is described by attributes.
66             self.lenfield_name = elt.get('value-mask-name')
67             self.lenfield_type = elt.get('value-mask-type')
68             self.lenwire = True
69             self.bitfield = True
70
71         elif elt.tag == 'op':
72             # Op field.  Need to recurse.
73             self.op = elt.get('op')
74             self.lhs = Expression(list(elt)[0], parent)
75             self.rhs = Expression(list(elt)[1], parent)
76
77             # Hopefully we don't have two separate length fields...
78             self.lenfield_name = self.lhs.lenfield_name
79             if self.lenfield_name == None:
80                 self.lenfield_name = self.rhs.lenfield_name
81
82         elif elt.tag == 'unop':
83             # Op field.  Need to recurse.
84             self.op = elt.get('op')
85             self.rhs = Expression(list(elt)[0], parent)
86
87             self.lenfield_name = self.rhs.lenfield_name
88             
89         elif elt.tag == 'value':
90             # Constant expression
91             self.nmemb = int(elt.text, 0)
92
93         elif elt.tag == 'popcount':
94             self.op = 'popcount'
95             self.rhs = Expression(list(elt)[0], parent)
96             self.lenfield_name = self.rhs.lenfield_name
97             # xcb_popcount returns 'int' - handle the type in the language-specific part
98
99         elif elt.tag == 'enumref':
100             self.op = 'enumref'
101             self.lenfield_name = (elt.get('ref'), elt.text)
102             
103         elif elt.tag == 'sumof':
104             self.op = 'sumof'
105             self.lenfield_name = elt.get('ref')
106
107         else:
108             # Notreached
109             raise Exception("undefined tag '%s'" % elt.tag)
110
111     def fixed_size(self):
112         return self.nmemb != None
113
114     def resolve(self, module, parents):
115         if self.op == 'enumref':
116             self.lenfield_type = module.get_type(self.lenfield_name[0])
117             self.lenfield_name = self.lenfield_name[1]
118         elif self.op == 'sumof':
119             # need to find the field with lenfield_name
120             for p in reversed(parents): 
121                 fields = dict([(f.field_name, f) for f in p.fields])
122                 if self.lenfield_name in fields.keys():
123                     if p.is_bitcase:
124                         # switch is the anchestor 
125                         self.lenfield_parent = p.parents[-1]
126                     else:
127                         self.lenfield_parent = p
128                     self.lenfield_type = fields[self.lenfield_name].field_type
129                     break
130