# base class for printing contents class ContentPrinter: def __init__(self): pass def print_content(self, content): return content # print integer-like values class IntPrinter(ContentPrinter): def __init__(self): super().__init__() def print_content(self, content): return hex(content) # print character class CharPrinter(ContentPrinter): def __init__(self): super().__init__() def print_content(self, content): return "'{:s}'".format(content) # print the struct class StructPrinter(ContentPrinter): def __init__(self): super().__init__() def print_content(self, content): str = "{\n" for rec in content: str += rec.print_content() + "\n" str += "}" class DummyRecord: def __init__(self, name, ctype, content, printer, comment=None): self.name = name self.ctype = ctype self.content = content self.printer = printer if comment is not None: self.comment = " /* {:s} */".format(comment) else: self.comment = "" def print_declaration(self, close_statment=True): decl = "{:s} {:s}".format(self.ctype, self.name) if close_statment: decl += ";" return decl def print_content(self): return "{:s}".format(self.printer.print_content(self.content)) # base class for a record class Record(DummyRecord): def __init__(self, name, ctype, content, printer, comment=None): super().__init__(name, ctype, content, printer, comment) self.array_like = isinstance(content, (list, set, tuple, str,)) self.type_encapsulates_arrayness = False self.typedef = None self.attribute = None def print_content(self): if not self.array_like: return self.printer.print_content(self.content) + self.comment else: str = "{ " first_line = True for element in self.content: if isinstance(element, DummyRecord): # printing non-primitive array-like types (e.g. struct); elements know how they get printed if first_line: str += self.comment str += "\n" str += "{:s}, //{:s}\n".format(element.print_content(), element.name) else: # printing primitives; elements need's parent printer str += "{:s}, ".format(self.printer.print_content(element)) + self.comment first_line = False str += "}" return str # get typename: if no typedef exists then return with ctype, if exists, return with typedef def get_typename(self): if self.typedef is None: return self.ctype else: return self.typedef # print variable declaration def print_declaration(self, close_statment=True, print_comment=True): decl = "{:s} {:s}".format(self.get_typename(), self.name) if self.array_like and not self.type_encapsulates_arrayness: decl += "[{:d}]".format(len(self.content)) if close_statment: decl += ";" if print_comment: decl += self.comment return decl # print variable assigment def print_assigment(self, close_statement=True): declaration = self.print_declaration(close_statment=False, print_comment=False) definition = self.print_content() statement = "{:s} = {:s}".format(declaration, definition) if close_statement: statement += ";" return statement # print a type definition based on the contents def print_typedef(self, tname=None): if tname is None: tname = self.typedef attribute_compound = "" if not self.attribute is None: attribute_compound = "__attribute__(({:s}))".format(self.attribute) tdef_clause = "typedef " if not self.array_like: tdef_clause += "{:s} {:s};".format(self.ctype, tname) else: array_of_primitives = not isinstance(self.content[0], Record) if array_of_primitives: tdef_clause += "{:s} {:s}[{:d}];".format(self.ctype, tname, len(self.content)) else: # array of structs (non-primitives) tdef_clause += self.ctype + " {" for rec in self.content: # tdef_clause += "{:s} {:s};\n".format(rec.ctype, rec.name) tdef_clause += rec.print_declaration(True) tdef_clause += "} " + "{:s} {:s};\n".format(attribute_compound, tname) return tdef_clause # structure record class StructRecord(Record): def __init__(self, name, ctype, content, comment=None): super().__init__(name, ctype, content, StructPrinter(), comment) self.type_encapsulates_arrayness = True # add new record to the structure def add_record(self, rec): self.content.append(rec) class RecordFactory: INT_LIKE_TYPES = ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"] BOOl_TYPES = ["bool", "b8"] STR_TYPE = "str" PLAIN_PRINTER = ContentPrinter() NUMERIC_PRINTER = IntPrinter() CHARACTER_PRINTER = CharPrinter() # Create record based on content and abbreviated type name # (also convert non-numeric types to numeric ones being having the same size) @staticmethod def create(name_arg0, ctype="", content="", no_autoconvert=False): # unpack params if isinstance(name_arg0, (list, set, tuple,)): name = name_arg0[0] ctype = name_arg0[1] content = name_arg0[2] if len(name_arg0) > 3: no_autoconvert = name_arg0[3] else: name = name_arg0 # determine standard c typename std_type = "error_type" printer = None # convert bool to int if RecordFactory.BOOl_TYPES.count(ctype) > 0: ctype = "u8" # convert string to character equivalent is_string = False if ctype == RecordFactory.STR_TYPE: is_string = True ctype = "u16" printer = CharPrinter() # auto-convert types if needed if is_string: content = str(content) elif isinstance(content, str) and not no_autoconvert: content = int(content, base=0) # auto-recognize base if no_autoconvert: printer = ContentPrinter() # loop-up standard c-type if RecordFactory.INT_LIKE_TYPES.count(ctype) > 0: # integer storage_size_str = ctype.strip("ui") if ctype[0] == 'u': std_type = ctype[0] + "int" + storage_size_str + "_t" else: std_type = "int" + storage_size_str + "_t" if printer is None: # if printer is not assigned yet printer = IntPrinter() # generate record rec = Record(name, std_type, content, printer) if no_autoconvert: rec.array_like = False return rec @staticmethod def createa(defs): recs = [] for rec in defs: recs.append(RecordFactory.create(rec)) return recs # # integer-like record # class IntRecord(Record): # def __init__(self, name, ctype, content): # super().__init__(name, ctype, content, IntPrinter()) # # # # string record # class StrRecord(Record): # def __init__(self, name, content): # super().__init__(name, "uint16_t", content, CharPrinter)