From 0366e7395c97e51b8a6294c10176bef73e1bdcf7 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 26 May 2010 12:19:58 +0200 Subject: Initial import of spice protocol description and demarshall generator The "spice.proto" file describes in detail the networking prototcol that spice uses and spice_codegen.py can parse this and generate demarshallers for such network messages. --- python_modules/ptypes.py | 965 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 965 insertions(+) create mode 100644 python_modules/ptypes.py (limited to 'python_modules/ptypes.py') diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py new file mode 100644 index 00000000..fe8a3212 --- /dev/null +++ b/python_modules/ptypes.py @@ -0,0 +1,965 @@ +import codegen +import types + +_types_by_name = {} +_types = [] + +def type_exists(name): + return _types_by_name.has_key(name) + +def lookup_type(name): + return _types_by_name[name] + +def get_named_types(): + return _types + +class FixedSize: + def __init__(self, val = 0, minor = 0): + if isinstance(val, FixedSize): + self.vals = val.vals + else: + self.vals = [0] * (minor + 1) + self.vals[minor] = val + + def __add__(self, other): + if isinstance(other, types.IntType): + other = FixedSize(other) + + new = FixedSize() + l = max(len(self.vals), len(other.vals)) + shared = min(len(self.vals), len(other.vals)) + + new.vals = [0] * l + + for i in range(shared): + new.vals[i] = self.vals[i] + other.vals[i] + + for i in range(shared,len(self.vals)): + new.vals[i] = self.vals[i]; + + for i in range(shared,len(other.vals)): + new.vals[i] = new.vals[i] + other.vals[i]; + + return new + + def __radd__(self, other): + return self.__add__(other) + + def __str__(self): + s = "%d" % (self.vals[0]) + + for i in range(1,len(self.vals)): + if self.vals[i] > 0: + s = s + " + ((minor >= %d)?%d:0)" % (i, self.vals[i]) + return s + +class Type: + def __init__(self): + self.attributes = {} + self.registred = False + self.name = None + + def has_name(self): + return self.name != None + + def get_type(self, recursive=False): + return self + + def is_primitive(self): + return False + + def is_fixed_sizeof(self): + return True + + def is_extra_size(self): + return False + + def contains_extra_size(self): + return False + + def is_fixed_nw_size(self): + return True + + def is_array(self): + return isinstance(self, ArrayType) + + def is_struct(self): + return isinstance(self, StructType) + + def is_pointer(self): + return isinstance(self, PointerType) + + def get_num_pointers(self): + return 0 + + def get_pointer_names(self): + return [] + + def sizeof(self): + return "sizeof(%s)" % (self.c_type()) + + def __repr__(self): + return self.__str__() + + def __str__(self): + if self.name != None: + return self.name + return "anonymous type" + + def resolve(self): + return self + + def register(self): + if self.registred or self.name == None: + return + self.registred = True + if _types_by_name.has_key(self.name): + raise Exception, "Type %s already defined" % self.name + _types.append(self) + _types_by_name[self.name] = self + + def has_pointer(self): + return False + + def has_attr(self, name): + return self.attributes.has_key(name) + +class TypeRef(Type): + def __init__(self, name): + Type.__init__(self) + self.name = name + + def __str__(self): + return "ref to %s" % (self.name) + + def resolve(self): + if not _types_by_name.has_key(self.name): + raise Exception, "Unknown type %s" % self.name + return _types_by_name[self.name] + + def register(self): + assert True, "Can't register TypeRef!" + + +class IntegerType(Type): + def __init__(self, bits, signed): + Type.__init__(self) + self.bits = bits + self.signed = signed + + if signed: + self.name = "int%d" % bits + else: + self.name = "uint%d" % bits + + def primitive_type(self): + return self.name + + def c_type(self): + return self.name + "_t" + + def get_fixed_nw_size(self): + return self.bits / 8 + + def is_primitive(self): + return True + +class TypeAlias(Type): + def __init__(self, name, the_type, attribute_list): + Type.__init__(self) + self.name = name + self.the_type = the_type + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def get_type(self, recursive=False): + if recursive: + return self.the_type.get_type(True) + else: + return self.the_type + + def primitive_type(self): + return self.the_type.primitive_type() + + def resolve(self): + self.the_type = self.the_type.resolve() + return self + + def __str__(self): + return "alias %s" % self.name + + def is_primitive(self): + return self.the_type.is_primitive() + + def is_fixed_sizeof(self): + return self.the_type.is_fixed_sizeof() + + def is_fixed_nw_size(self): + return self.the_type.is_fixed_nw_size() + + def get_fixed_nw_size(self): + return self.the_type.get_fixed_nw_size() + + def get_num_pointers(self): + return self.the_type.get_num_pointers() + + def get_pointer_names(self): + return self.the_type.get_pointer_names() + + def c_type(self): + if self.has_attr("ctype"): + return self.attributes["ctype"][0] + return self.name + + def has_pointer(self): + return self.the_type.has_pointer() + +class EnumBaseType(Type): + def is_enum(self): + return isinstance(self, EnumType) + + def primitive_type(self): + return "uint%d" % (self.bits) + + def c_type(self): + return "uint%d_t" % (self.bits) + + def c_name(self): + return codegen.prefix_camel(self.name) + + def c_enumname(self, value): + if self.has_attr("prefix"): + return self.attributes["prefix"][0] + self.names[value] + return codegen.prefix_underscore_upper(self.name.upper(), self.names[value]) + + def c_enumname_by_name(self, name): + if self.has_attr("prefix"): + return self.attributes["prefix"][0] + self.names[value] + return codegen.prefix_underscore_upper(self.name.upper(), name) + + def is_primitive(self): + return True + + def get_fixed_nw_size(self): + return self.bits / 8 + +class EnumType(EnumBaseType): + def __init__(self, bits, name, enums, attribute_list): + Type.__init__(self) + self.bits = bits + self.name = name + + last = -1 + names = {} + values = {} + for v in enums: + name = v[0] + if len(v) > 1: + value = v[1] + else: + value = last + 1 + last = value + + assert not names.has_key(value) + names[value] = name + values[name] = value + + self.names = names + self.values = values + + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def __str__(self): + return "enum %s" % self.name + + def c_define(self, writer): + writer.write("enum ") + writer.write(self.c_name()) + writer.begin_block() + values = self.names.keys() + values.sort() + current_default = 0 + for i in values: + writer.write(self.c_enumname(i)) + if i != current_default: + writer.write(" = %d" % (i)) + writer.write(",") + writer.newline() + current_default = i + 1 + writer.newline() + writer.write(codegen.prefix_underscore_upper(self.name.upper(), "ENUM_END")) + writer.newline() + writer.end_block(semicolon=True) + writer.newline() + +class FlagsType(EnumBaseType): + def __init__(self, bits, name, flags, attribute_list): + Type.__init__(self) + self.bits = bits + self.name = name + + last = -1 + names = {} + values = {} + for v in flags: + name = v[0] + if len(v) > 1: + value = v[1] + else: + value = last + 1 + last = value + + assert not names.has_key(value) + names[value] = name + values[name] = value + + self.names = names + self.values = values + + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def __str__(self): + return "flags %s" % self.name + + def c_define(self, writer): + writer.write("enum ") + writer.write(self.c_name()) + writer.begin_block() + values = self.names.keys() + values.sort() + mask = 0 + for i in values: + writer.write(self.c_enumname(i)) + mask = mask | (1< 0 + + def is_image_size_length(self): + if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType): + return False + return self.size[0] == "image_size" + + def is_bytes_length(self): + if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType): + return False + return self.size[0] == "bytes" + + def is_cstring_length(self): + if isinstance(self.size, types.IntType) or isinstance(self.size, types.StringType): + return False + return self.size[0] == "cstring" + + def is_fixed_sizeof(self): + return self.is_constant_length() and self.element_type.is_fixed_sizeof() + + def is_fixed_nw_size(self): + return self.is_constant_length() and self.element_type.is_fixed_nw_size() + + def get_fixed_nw_size(self): + if not self.is_fixed_nw_size(): + raise Exception, "Not a fixed size type" + + return self.element_type.get_fixed_nw_size() * self.size + + def get_num_pointers(self): + element_count = self.element_type.get_num_pointers() + if element_count == 0: + return 0 + if self.is_constant_length(self): + return element_count * self.size + raise Exception, "Pointers in dynamic arrays not supported" + + def get_pointer_names(self): + element_count = self.element_type.get_num_pointers() + if element_count == 0: + return [] + raise Exception, "Pointer names in arrays not supported" + + def contains_extra_size(self): + return self.element_type.contains_extra_size() + + def sizeof(self): + return "%s * %s" % (self.element_type.sizeof(), self.size) + + def c_type(self): + return self.element_type.c_type() + +class PointerType(Type): + def __init__(self, target_type): + Type.__init__(self) + self.name = None + self.target_type = target_type + + def __str__(self): + return "%s*" % (str(self.target_type)) + + def resolve(self): + self.target_type = self.target_type.resolve() + return self + + def get_fixed_size(self): + return 8 # offsets are 64bit + + def is_fixed_nw_size(self): + return True + + def is_primitive(self): + return True + + def primitive_type(self): + return "uint64" + + def get_fixed_nw_size(self): + return 8 + + def c_type(self): + return "SPICE_ADDRESS" + + def has_pointer(self): + return True + + def contains_extra_size(self): + return True + + def get_num_pointers(self): + return 1 + +class Containee: + def __init__(self): + self.attributes = {} + + def is_switch(self): + return False + + def is_pointer(self): + return not self.is_switch() and self.member_type.is_pointer() + + def is_array(self): + return not self.is_switch() and self.member_type.is_array() + + def is_struct(self): + return not self.is_switch() and self.member_type.is_struct() + + def is_primitive(self): + return not self.is_switch() and self.member_type.is_primitive() + + def has_attr(self, name): + return self.attributes.has_key(name) + + def has_minor_attr(self): + return self.has_attr("minor") + + def has_end_attr(self): + return self.has_attr("end") + + def get_minor_attr(self): + return self.attributes["minor"][0] + +class Member(Containee): + def __init__(self, name, member_type, attribute_list): + Containee.__init__(self) + self.name = name + self.member_type = member_type + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def resolve(self, container): + self.container = container + self.member_type = self.member_type.resolve() + self.member_type.register() + return self + + def is_primitive(self): + return self.member_type.is_primitive() + + def is_fixed_sizeof(self): + if self.has_end_attr(): + return False + return self.member_type.is_fixed_sizeof() + + def is_extra_size(self): + return self.has_end_attr() + + def is_fixed_nw_size(self): + return self.member_type.is_fixed_nw_size() + + def get_fixed_nw_size(self): + size = self.member_type.get_fixed_nw_size() + if self.has_minor_attr(): + minor = self.get_minor_attr() + size = FixedSize(size, minor) + return size + + def contains_extra_size(self): + return self.member_type.contains_extra_size() + + def sizeof(self): + return self.member_type.sizeof() + + def __repr__(self): + return "%s (%s)" % (str(self.name), str(self.member_type)) + + def has_pointer(self): + return self.member_type.has_pointer() + + def get_num_pointers(self): + return self.member_type.get_num_pointers() + + def get_pointer_names(self): + if self.member_type.is_pointer(): + names = [self.name + "_out"] + else: + names = self.member_type.get_pointer_names() + if self.has_attr("outvar"): + prefix = self.attributes["outvar"][0] + names = map(lambda name: prefix + "_" + name, names) + return names + +class SwitchCase: + def __init__(self, values, member): + self.values = values + self.member = member + self.members = [member] + + def get_check(self, var_cname, var_type): + checks = [] + for v in self.values: + if v == None: + return "1" + elif var_type.is_enum(): + checks.append("%s == %s" % (var_cname, var_type.c_enumname_by_name(v))) + else: + checks.append("(%s & %s)" % (var_cname, var_type.c_enumname_by_name(v))) + return " || ".join(checks) + + def resolve(self, container): + self.switch = container + self.member = self.member.resolve(self) + return self + + def has_pointer(self): + return self.member.has_pointer() + + def get_num_pointers(self): + return self.member.get_num_pointers() + + def get_pointer_names(self): + return self.member.get_pointer_names() + +class Switch(Containee): + def __init__(self, variable, cases, name, attribute_list): + Containee.__init__(self) + self.variable = variable + self.name = name + self.cases = cases + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def is_switch(self): + return True + + def has_switch_member(self, member): + for c in self.cases: + if c.member == member: + return True + return False + + def resolve(self, container): + self.container = container + self.cases = map(lambda c : c.resolve(self), self.cases) + return self + + def __repr__(self): + return "switch on %s %s" % (str(self.variable),str(self.name)) + + def is_fixed_sizeof(self): + # Kinda weird, but we're unlikely to have a real struct if there is an @end + if self.has_end_attr(): + return False + return True + + def is_fixed_nw_size(self): + if self.has_attr("fixedsize"): + return True + + size = None + for c in self.cases: + if not c.member.is_fixed_nw_size(): + return False + if size == None: + size = c.member.get_fixed_nw_size() + elif size != c.member.get_fixed_nw_size(): + return False + return True + + def is_extra_size(self): + return self.has_end_attr() + + def contains_extra_size(self): + for c in self.cases: + if c.member.is_extra_size(): + return True + if c.member.contains_extra_size(): + return True + return False + + def get_fixed_nw_size(self): + if not self.is_fixed_nw_size(): + raise Exception, "Not a fixed size type" + size = 0; + for c in self.cases: + size = max(size, c.member.get_fixed_nw_size()) + return size + + def sizeof(self): + return "sizeof(((%s *)NULL)->%s)" % (self.container.c_type(), + self.name) + + def has_pointer(self): + for c in self.cases: + if c.has_pointer(): + return True + return False + + def get_num_pointers(self): + count = 0 + for c in self.cases: + count = max(count, c.get_num_pointers()) + return count + + def get_pointer_names(self): + names = [] + for c in self.cases: + names = names + c.get_pointer_names() + return names + +class ContainerType(Type): + def is_fixed_sizeof(self): + for m in self.members: + if not m.is_fixed_sizeof(): + return False + return True + + def contains_extra_size(self): + for m in self.members: + if m.is_extra_size(): + return True + if m.contains_extra_size(): + return True + return False + + def is_fixed_nw_size(self): + for i in self.members: + if not i.is_fixed_nw_size(): + return False + return True + + def get_fixed_nw_size(self): + size = 0 + for i in self.members: + size = size + i.get_fixed_nw_size() + return size + + def get_fixed_nw_offset(self, member): + size = 0 + for i in self.members: + if i == member: + break + if i.is_fixed_nw_size(): + size = size + i.get_fixed_nw_size() + return size + + def resolve(self): + self.members = map(lambda m : m.resolve(self), self.members) + return self + + def get_num_pointers(self): + count = 0 + for m in self.members: + count = count + m.get_num_pointers() + return count + + def get_pointer_names(self): + names = [] + for m in self.members: + names = names + m.get_pointer_names() + return names + + def has_pointer(self): + for m in self.members: + if m.has_pointer(): + return True + return False + + def get_nw_offset(self, member, prefix = "", postfix = ""): + fixed = self.get_fixed_nw_offset(member) + v = [] + for m in self.members: + if m == member: + break + if m.is_switch() and m.has_switch_member(member): + break + if not m.is_fixed_nw_size(): + v.append(prefix + m.name + postfix) + if len(v) > 0: + return str(fixed) + " + " + (" + ".join(v)) + else: + return str(fixed) + + def lookup_member(self, name): + return self.members_by_name[name] + +class StructType(ContainerType): + def __init__(self, name, members, attribute_list): + Type.__init__(self) + self.name = name + self.members = members + self.members_by_name = {} + for m in members: + self.members_by_name[m.name] = m + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def __str__(self): + if self.name == None: + return "anonymous struct" + else: + return "struct %s" % self.name + + def c_type(self): + if self.has_attr("ctype"): + return self.attributes["ctype"][0] + return codegen.prefix_camel(self.name) + +class MessageType(ContainerType): + def __init__(self, name, members, attribute_list): + Type.__init__(self) + self.name = name + self.members = members + self.members_by_name = {} + for m in members: + self.members_by_name[m.name] = m + self.reverse_members = {} # ChannelMembers referencing this message + for attr in attribute_list: + self.attributes[attr[0][1:]] = attr[1:] + + def __str__(self): + if self.name == None: + return "anonymous message" + else: + return "message %s" % self.name + + def c_name(self): + if self.name == None: + cms = self.reverse_members.keys() + if len(cms) != 1: + raise "Unknown typename for message" + cm = cms[0] + channelname = cm.channel.member_name + if channelname == None: + channelname = "" + else: + channelname = channelname + "_" + if cm.is_server: + return "msg_" + channelname + cm.name + else: + return "msgc_" + channelname + cm.name + else: + return codegen.prefix_camel("Msg", self.name) + + def c_type(self): + if self.has_attr("ctype"): + return self.attributes["ctype"][0] + if self.name == None: + cms = self.reverse_members.keys() + if len(cms) != 1: + raise "Unknown typename for message" + cm = cms[0] + channelname = cm.channel.member_name + if channelname == None: + channelname = "" + if cm.is_server: + return codegen.prefix_camel("Msg", channelname, cm.name) + else: + return codegen.prefix_camel("Msgc", channelname, cm.name) + else: + return codegen.prefix_camel("Msg", self.name) + +class ChannelMember(Containee): + def __init__(self, name, message_type, value): + Containee.__init__(self) + self.name = name + self.message_type = message_type + self.value = value + + def resolve(self, channel): + self.channel = channel + self.message_type = self.message_type.resolve() + self.message_type.reverse_members[self] = 1 + + return self + + def __repr__(self): + return "%s (%s)" % (str(self.name), str(self.message_type)) + +class ChannelType(Type): + def __init__(self, name, base, members): + Type.__init__(self) + self.name = name + self.base = base + self.member_name = None + self.members = members + + def __str__(self): + if self.name == None: + return "anonymous channel" + else: + return "channel %s" % self.name + + def is_fixed_nw_size(self): + return False + + def get_client_message(self, name): + return self.client_messages_byname[name] + + def get_server_message(self, name): + return self.server_messages_byname[name] + + def resolve(self): + if self.base != None: + self.base = self.base.resolve() + + server_messages = self.base.server_messages[:] + server_messages_byname = self.base.server_messages_byname.copy() + client_messages = self.base.client_messages[:] + client_messages_byname = self.base.client_messages_byname.copy() + else: + server_messages = [] + server_messages_byname = {} + client_messages = [] + client_messages_byname = {} + + server_count = 1 + client_count = 1 + + server = True + for m in self.members: + if m == "server": + server = True + elif m == "client": + server = False + elif server: + m.is_server = True + m = m.resolve(self) + if m.value: + server_count = m.value + 1 + else: + m.value = server_count + server_count = server_count + 1 + server_messages.append(m) + server_messages_byname[m.name] = m + else: + m.is_server = False + m = m.resolve(self) + if m.value: + client_count = m.value + 1 + else: + m.value = client_count + client_count = client_count + 1 + client_messages.append(m) + client_messages_byname[m.name] = m + + self.server_messages = server_messages + self.server_messages_byname = server_messages_byname + self.client_messages = client_messages + self.client_messages_byname = client_messages_byname + + return self + +class ProtocolMember: + def __init__(self, name, channel_type, value): + self.name = name + self.channel_type = channel_type + self.value = value + + def resolve(self, protocol): + self.channel_type = self.channel_type.resolve() + assert(self.channel_type.member_name == None) + self.channel_type.member_name = self.name + return self + + def __repr__(self): + return "%s (%s)" % (str(self.name), str(self.channel_type)) + +class ProtocolType(Type): + def __init__(self, name, channels): + Type.__init__(self) + self.name = name + self.channels = channels + + def __str__(self): + if self.name == None: + return "anonymous protocol" + else: + return "protocol %s" % self.name + + def is_fixed_nw_size(self): + return False + + def resolve(self): + count = 1 + for m in self.channels: + m = m.resolve(self) + if m.value: + count = m.value + 1 + else: + m.value = count + count = count + 1 + + return self + +int8 = IntegerType(8, True) +uint8 = IntegerType(8, False) +int16 = IntegerType(16, True) +uint16 = IntegerType(16, False) +int32 = IntegerType(32, True) +uint32 = IntegerType(32, False) +int64 = IntegerType(64, True) +uint64 = IntegerType(64, False) -- cgit