class ListType(Type): ''' Derived class which represents a list of some other datatype. Fixed- or variable-sized. Public fields added: member is the datatype of the list elements. parent is the structure type containing the list. expr is an Expression object containing the length information, for variable-sized lists. ''' def __init__(self, elt, member, *parent): Type.__init__(self, member.name) self.is_list = True self.member = member self.parents = list(parent) lenfield_name = False if elt.tag == 'list': elts = list(elt) self.expr = Expression(elts[0] if len(elts) else elt, self) is_list_in_parent = self.parents[0].elt.tag in ('request', 'event', 'reply', 'error') if not len(elts) and is_list_in_parent: self.expr = Expression(elt,self) self.expr.op = 'calculate_len' else: self.expr = Expression(elts[0] if len(elts) else elt, self) self.size = member.size if member.fixed_size() else None self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None self.required_start_align = self.member.required_start_align def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None): if not self.fixed_size(): # We need a length field. # Ask our Expression object for it's name, type, and whether it's on the wire. lenfid = self.expr.lenfield_type lenfield_name = self.expr.lenfield_name lenwire = self.expr.lenwire needlen = True # See if the length field is already in the structure. for parent in self.parents: for field in parent.fields: if field.field_name == lenfield_name: needlen = False # It isn't, so we need to add it to the structure ourself. if needlen: type = module.get_type(lenfid) lenfield_type = module.get_type_name(lenfid) type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum) # Add ourself to the structure by calling our original method. Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum) def resolve(self, module): if self.resolved: return self.member.resolve(module) self.expr.resolve(module, self.parents) self.required_start_align = self.member.required_start_align # Find my length field again. We need the actual Field object in the expr. # This is needed because we might have added it ourself above. if not self.fixed_size(): for parent in self.parents: for field in parent.fields: if field.field_name == self.expr.lenfield_name and field.wire: self.expr.lenfield = field break self.resolved = True def fixed_size(self): return self.member.fixed_size() and self.expr.fixed_size() def unchecked_get_alignment_after(self, start_align, callstack, log): my_callstack = callstack[:] my_callstack.append(self) if start_align is None: log.fail(start_align, "", self, my_callstack, "start_align is None") return None if self.expr.fixed_size(): # fixed number of elements num_elements = self.nmemb prev_alignment = None alignment = start_align while num_elements > 0: if alignment is None: if log is not None: log.fail(start_align, "", self, my_callstack, ("fixed size list with size %d after %d iterations" + ", at transition from alignment \"%s\"") % (self.nmemb, (self.nmemb - num_elements), str(prev_alignment))) return None prev_alignment = alignment alignment = self.member.get_alignment_after(prev_alignment, my_callstack, log) num_elements -= 1 if log is not None: log.ok(start_align, "", self, my_callstack, alignment) return alignment else: # variable number of elements # check whether the number of elements is a multiple multiple = self.expr.get_multiple() assert multiple > 0 # iterate until the combined alignment does not change anymore alignment = start_align while True: prev_multiple_alignment = alignment # apply "multiple" amount of changes sequentially prev_alignment = alignment for multiple_count in range(0, multiple): after_alignment = self.member.get_alignment_after(prev_alignment, my_callstack, log) if after_alignment is None: if log is not None: log.fail(start_align, "", self, my_callstack, ("variable size list " + "at transition from alignment \"%s\"") % (str(prev_alignment))) return None prev_alignment = after_alignment # combine with the cumulatively combined alignment # (to model the variable number of entries) alignment = prev_multiple_alignment.combine_with(after_alignment) if alignment == prev_multiple_alignment: # does not change anymore by adding more potential elements # -> finished if log is not None: log.ok(start_align, "", self, my_callstack, alignment) return alignment
class ListType(Type): ''' Derived class which represents a list of some other datatype. Fixed- or variable-sized. Public fields added: member is the datatype of the list elements. parent is the structure type containing the list. expr is an Expression object containing the length information, for variable-sized lists. ''' def __init__(self, elt, member, *parent): Type.__init__(self, member.name) self.is_list = True self.member = member self.parents = list(parent) if elt.tag == 'list': elts = list(elt) self.expr = Expression(elts[0] if len(elts) else elt, self) self.size = member.size if member.fixed_size() else None self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None): if not self.fixed_size(): # We need a length field. # Ask our Expression object for it's name, type, and whether it's on the wire. lenfid = self.expr.lenfield_type lenfield_name = self.expr.lenfield_name lenwire = self.expr.lenwire needlen = True # See if the length field is already in the structure. for parent in self.parents: for field in parent.fields: if field.field_name == lenfield_name: needlen = False # It isn't, so we need to add it to the structure ourself. if needlen: type = module.get_type(lenfid) lenfield_type = module.get_type_name(lenfid) type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum) # Add ourself to the structure by calling our original method. Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum) def resolve(self, module): if self.resolved: return self.member.resolve(module) self.expr.resolve(module, self.parents) # Find my length field again. We need the actual Field object in the expr. # This is needed because we might have added it ourself above. if not self.fixed_size(): for parent in self.parents: for field in parent.fields: if field.field_name == self.expr.lenfield_name and field.wire: self.expr.lenfield = field break self.resolved = True def fixed_size(self): return self.member.fixed_size() and self.expr.fixed_size()
class ListType(Type): ''' Derived class which represents a list of some other datatype. Fixed- or variable-sized. Public fields added: member is the datatype of the list elements. parent is the structure type containing the list. expr is an Expression object containing the length information, for variable-sized lists. ''' def __init__(self, elt, member, *parent): Type.__init__(self, member.name) self.is_list = True self.member = member self.parents = list(parent) lenfield_name = False if elt.tag == 'list': elts = list(elt) self.expr = Expression(elts[0] if len(elts) else elt, self) is_list_in_parent = self.parents[0].elt.tag in ('request', 'event', 'reply', 'error') if not len(elts) and is_list_in_parent: self.expr = Expression(elt, self) self.expr.op = 'calculate_len' else: self.expr = Expression(elts[0] if len(elts) else elt, self) self.size = member.size if member.fixed_size() else None self.nmemb = self.expr.nmemb if self.expr.fixed_size() else None self.required_start_align = self.member.required_start_align def make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum=None): if not self.fixed_size(): # We need a length field. # Ask our Expression object for it's name, type, and whether it's on the wire. lenfid = self.expr.lenfield_type lenfield_name = self.expr.lenfield_name lenwire = self.expr.lenwire needlen = True # See if the length field is already in the structure. for parent in self.parents: for field in parent.fields: if field.field_name == lenfield_name: needlen = False # It isn't, so we need to add it to the structure ourself. if needlen: type = module.get_type(lenfid) lenfield_type = module.get_type_name(lenfid) type.make_member_of(module, complex_type, lenfield_type, lenfield_name, True, lenwire, False, enum) # Add ourself to the structure by calling our original method. Type.make_member_of(self, module, complex_type, field_type, field_name, visible, wire, auto, enum) def resolve(self, module): if self.resolved: return self.member.resolve(module) self.expr.resolve(module, self.parents) self.required_start_align = self.member.required_start_align # Find my length field again. We need the actual Field object in the expr. # This is needed because we might have added it ourself above. if not self.fixed_size(): for parent in self.parents: for field in parent.fields: if field.field_name == self.expr.lenfield_name and field.wire: self.expr.lenfield = field break self.resolved = True def fixed_size(self): return self.member.fixed_size() and self.expr.fixed_size() def unchecked_get_alignment_after(self, start_align, callstack, log): my_callstack = callstack[:] my_callstack.append(self) if start_align is None: log.fail(start_align, "", self, my_callstack, "start_align is None") return None if self.expr.fixed_size(): # fixed number of elements num_elements = self.nmemb prev_alignment = None alignment = start_align while num_elements > 0: if alignment is None: if log is not None: log.fail( start_align, "", self, my_callstack, ("fixed size list with size %d after %d iterations" + ", at transition from alignment \"%s\"") % (self.nmemb, (self.nmemb - num_elements), str(prev_alignment))) return None prev_alignment = alignment alignment = self.member.get_alignment_after( prev_alignment, my_callstack, log) num_elements -= 1 if log is not None: log.ok(start_align, "", self, my_callstack, alignment) return alignment else: # variable number of elements # check whether the number of elements is a multiple multiple = self.expr.get_multiple() assert multiple > 0 # iterate until the combined alignment does not change anymore alignment = start_align while True: prev_multiple_alignment = alignment # apply "multiple" amount of changes sequentially prev_alignment = alignment for multiple_count in range(0, multiple): after_alignment = self.member.get_alignment_after( prev_alignment, my_callstack, log) if after_alignment is None: if log is not None: log.fail(start_align, "", self, my_callstack, ("variable size list " + "at transition from alignment \"%s\"") % (str(prev_alignment))) return None prev_alignment = after_alignment # combine with the cumulatively combined alignment # (to model the variable number of entries) alignment = prev_multiple_alignment.combine_with( after_alignment) if alignment == prev_multiple_alignment: # does not change anymore by adding more potential elements # -> finished if log is not None: log.ok(start_align, "", self, my_callstack, alignment) return alignment