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