flatUSB/desc/StructGenerator.py
2024-04-08 19:25:47 +02:00

236 lines
7.4 KiB
Python

# 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)