1''' 2This module contains helper classes for structure fields and length expressions. 3''' 4class 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 self.parent = None 26 27 def __str__(self): 28 field_string = "Field" 29 if self.field_name is None: 30 if self.field_type is not None: 31 field_string += " with type " + str(self.type) 32 else: 33 field_string += " \"" + self.field_name + "\"" 34 if self.parent is not None: 35 field_string += " in " + str(self.parent) 36 37 return field_string 38 39class Expression(object): 40 ''' 41 Represents a mathematical expression for a list length or exprfield. 42 43 Public fields: 44 op is the operation (text +,*,/,<<,~) or None. 45 lhs and rhs are the sub-Expressions if op is set. 46 lenfield_name is the name of the length field, or None for request lists. 47 lenfield is the Field object for the length field, or None. 48 bitfield is True if the length field is a bitmask instead of a number. 49 nmemb is the fixed size (value)of the expression, or None 50 ''' 51 def __init__(self, elt, parent): 52 self.parent = parent 53 54 self.nmemb = None 55 56 self.lenfield_name = None 57 self.lenfield_type = None 58 self.lenfield_parent = None 59 self.lenfield = None 60 self.lenwire = False 61 self.bitfield = False 62 63 self.op = None 64 self.lhs = None 65 self.rhs = None 66 67 self.contains_listelement_ref = False 68 69 if elt.tag == 'list': 70 # List going into a request, which has no length field (inferred by server) 71 self.lenfield_name = elt.get('name') + '_len' 72 self.lenfield_type = 'CARD32' 73 74 elif elt.tag == 'fieldref': 75 # Standard list with a fieldref 76 self.lenfield_name = elt.text 77 78 elif elt.tag == 'paramref': 79 self.lenfield_name = elt.text 80 self.lenfield_type = elt.get('type') 81 82 elif elt.tag == 'op': 83 # Op field. Need to recurse. 84 self.op = elt.get('op') 85 self.lhs = Expression(list(elt)[0], parent) 86 self.rhs = Expression(list(elt)[1], parent) 87 88 # Hopefully we don't have two separate length fields... 89 self.lenfield_name = self.lhs.lenfield_name 90 if self.lenfield_name == None: 91 self.lenfield_name = self.rhs.lenfield_name 92 93 elif elt.tag == 'unop': 94 # Op field. Need to recurse. 95 self.op = elt.get('op') 96 self.rhs = Expression(list(elt)[0], parent) 97 98 self.lenfield_name = self.rhs.lenfield_name 99 100 elif elt.tag == 'value': 101 # Constant expression 102 self.nmemb = int(elt.text, 0) 103 104 elif elt.tag == 'popcount': 105 self.op = 'popcount' 106 self.rhs = Expression(list(elt)[0], parent) 107 self.lenfield_name = self.rhs.lenfield_name 108 # xcb_popcount returns 'int' - handle the type in the language-specific part 109 110 elif elt.tag == 'enumref': 111 self.op = 'enumref' 112 self.lenfield_name = (elt.get('ref'), elt.text) 113 114 elif elt.tag == 'sumof': 115 self.op = 'sumof' 116 self.lenfield_name = elt.get('ref') 117 subexpressions = list(elt) 118 if len(subexpressions) > 0: 119 # sumof with a nested expression which is to be evaluated 120 # for each list-element in the context of that list-element. 121 # sumof then returns the sum of the results of these evaluations 122 self.rhs = Expression(subexpressions[0], parent) 123 124 elif elt.tag == 'listelement-ref': 125 # current list element inside iterating expressions such as sumof 126 self.op = 'listelement-ref' 127 self.contains_listelement_ref = True 128 129 else: 130 # Notreached 131 raise Exception("undefined tag '%s'" % elt.tag) 132 133 def fixed_size(self): 134 return self.nmemb != None 135 136 def get_value(self): 137 return self.nmemb 138 139 # if the value of the expression is a guaranteed multiple of a number 140 # return this number, else return 1 (which is trivially guaranteed for integers) 141 def get_multiple(self): 142 multiple = 1 143 if self.op == '*': 144 if self.lhs.fixed_size(): 145 multiple *= self.lhs.get_value() 146 if self.rhs.fixed_size(): 147 multiple *= self.rhs.get_value() 148 149 return multiple 150 151 def recursive_resolve_tasks(self, module, parents): 152 for subexpr in (self.lhs, self.rhs): 153 if subexpr != None: 154 subexpr.recursive_resolve_tasks(module, parents) 155 self.contains_listelement_ref |= subexpr.contains_listelement_ref 156 157 def resolve(self, module, parents): 158 if self.op == 'enumref': 159 self.lenfield_type = module.get_type(self.lenfield_name[0]) 160 self.lenfield_name = self.lenfield_name[1] 161 elif self.op == 'sumof': 162 # need to find the field with lenfield_name 163 for p in reversed(parents): 164 fields = dict([(f.field_name, f) for f in p.fields]) 165 if self.lenfield_name in fields.keys(): 166 if p.is_case_or_bitcase: 167 # switch is the anchestor 168 self.lenfield_parent = p.parents[-1] 169 else: 170 self.lenfield_parent = p 171 self.lenfield_type = fields[self.lenfield_name].field_type 172 self.lenfield = fields[self.lenfield_name] 173 break 174 175 self.recursive_resolve_tasks(module, parents) 176 177