def translate_struct(self, struct): def gen_member(member, padder): def build_annotation(member): if member.size: if member.bound: annotation = 'limited array, size in {}'.format( member.bound) else: annotation = '' else: if member.bound: annotation = 'dynamic array, size in {}'.format( member.bound) else: annotation = 'greedy array' return annotation typename = primitive_types.get(member.type_name, member.type_name) if member.is_array: annotation = build_annotation(member) size = member.size or 1 if annotation: field = '{0} {1}[{2}]; /// {3}\n'.format( typename, member.name, size, annotation) else: field = '{0} {1}[{2}];\n'.format(typename, member.name, size) else: field = '{0} {1};\n'.format(typename, member.name) if member.optional: field = 'prophy::bool_t has_{0};\n'.format(member.name) + field if member.padding is not None and member.padding > 0: field += padder.generate_padding(member.padding) return field def gen_block(members, padder): generated = (gen_member(member, padder) for member in members) return _indent(''.join(generated), 4) def gen_part(index, part, padder): generated = STRUCT_DEF_PART_TEMPLATE.format( index=index + 2, block=gen_block(part, padder), align=part[0].alignment) return _indent(generated, 4) main, parts = model.partition(struct.members) padder = _Padder() blocks = '\n'.join([gen_block(main, padder)] + [ gen_part(index, part, padder) for index, part in enumerate(parts) ]) return STRUCT_DEF_TEMPLATE.format(align=struct.alignment, name=struct.name, blocks=blocks)
def _generate_def_struct(struct): def gen_member(member, padder): def build_annotation(member): if member.size: if member.bound: annotation = 'limited array, size in {}'.format( member.bound) else: annotation = '' else: if member.bound: annotation = 'dynamic array, size in {}'.format( member.bound) else: annotation = 'greedy array' return annotation typename = primitive_types.get(member.type_, member.type_) if member.array: annotation = build_annotation(member) size = member.size or 1 if annotation: field = '{0} {1}[{2}]; /// {3}\n'.format( typename, member.name, size, annotation) else: field = '{0} {1}[{2}];\n'.format(typename, member.name, size) else: field = '{0} {1};\n'.format(typename, member.name) if member.optional: field = 'prophy::bool_t has_{0};\n'.format(member.name) + field if member.padding > 0: field += padder.generate_padding(member.padding) return field def gen_block(members, padder): generated = (gen_member(member, padder) for member in members) return _indent(''.join(generated), 4) def gen_part(index, part, padder): generated = 'PROPHY_STRUCT({2}) part{0}\n{{\n{1}}} _{0};\n'.format( index + 2, gen_block(part, padder), part[0].alignment) return _indent(generated, 4) main, parts = model.partition(struct.members) padder = _Padder() blocks = ( [gen_block(main, padder)] + [gen_part(index, part, padder) for index, part in enumerate(parts)]) return 'PROPHY_STRUCT(%s) %s\n{\n%s};' % (struct.alignment, struct.name, '\n'.join(blocks))
def test_partition_fixed(): nodes = [ model.Struct("Fixed", [ model.StructMember("a", "u8"), model.StructMember("b", "u8"), model.StructMember("c", "u8") ]) ] model.cross_reference(nodes) model.evaluate_kinds(nodes) main, parts = model.partition(nodes[0].members) assert [x.name for x in main] == ["a", "b", "c"] assert [[x.name for x in part] for part in parts] == []
def test_partition_many_arrays_mixed(): nodes = [ model.Struct("ManyArraysMixed", [ model.StructMember("num_of_a", "u8"), model.StructMember("num_of_b", "u8"), model.StructMember("a", "u8", bound = "num_of_a"), model.StructMember("b", "u8", bound = "num_of_b") ]), ] model.cross_reference(nodes) model.evaluate_kinds(nodes) main, parts = model.partition(nodes[0].members) assert [x.name for x in main] == ["num_of_a", "num_of_b", "a"] assert [[x.name for x in part] for part in parts] == [["b"]]
def test_partition_many_dynamic_structs(): nodes = [ model.Struct("Dynamic", [ model.StructMember("num_of_a", "u8"), model.StructMember("a", "u8", bound = "num_of_a") ]), model.Struct("X", [ model.StructMember("a", "Dynamic"), model.StructMember("b", "Dynamic"), model.StructMember("c", "Dynamic") ]) ] model.cross_reference(nodes) model.evaluate_kinds(nodes) main, parts = model.partition(nodes[1].members) assert [x.name for x in main] == ["a"] assert [[x.name for x in part] for part in parts] == [["b"], ["c"]]
def _generate_def_struct(struct): def gen_member(member): def build_annotation(member): if member.size: if member.bound: annotation = 'limited array, size in {}'.format(member.bound) else: annotation = '' else: if member.bound: annotation = 'dynamic array, size in {}'.format(member.bound) else: annotation = 'greedy array' return annotation typename = primitive_types.get(member.type_, member.type_) if member.array: annotation = build_annotation(member) size = member.size or 1 if annotation: field = '{0} {1}[{2}]; /// {3}\n'.format(typename, member.name, size, annotation) else: field = '{0} {1}[{2}];\n'.format(typename, member.name, size) else: field = '{0} {1};\n'.format(typename, member.name) if member.optional: return 'prophy::bool_t has_{0};\n'.format(member.name) + field return field def gen_part(i, part): generated = 'struct part{0}\n{{\n{1}}} _{0};'.format( i + 2, _indent(''.join(map(gen_member, part)), 4) ) return _indent(generated, 4) main, parts = model.partition(struct.members) generated = _indent(''.join(map(gen_member, main)), 4) if parts: generated += '\n' + '\n\n'.join(map(gen_part, range(len(parts)), parts)) + '\n' return 'struct {}\n{{\n{}}};'.format(struct.name, generated)
def _generate_swap_struct(struct): def gen_member(member, delimiters = []): if member.array: is_dynamic = member.kind == model.Kind.DYNAMIC swap_mode = 'dynamic' if is_dynamic else 'fixed' if member.bound: bound = member.bound if member.bound not in delimiters: bound = 'payload->' + bound return 'swap_n_{0}({1}, {2})'.format( swap_mode, _member_access_statement(member), bound) elif not member.bound and member.size: return 'swap_n_{0}({1}, {2})'.format( swap_mode, _member_access_statement(member), member.size) else: if member.optional: preamble = 'swap(&payload->has_{0});\nif (payload->has_{0}) '.format(member.name) else: preamble = '' return preamble + 'swap({0})'.format(_member_access_statement(member)) def gen_last_member(name, last_mem, delimiters = []): if last_mem.kind == model.Kind.UNLIMITED or last_mem.greedy: return 'return cast<{0}*>({1});\n'.format( name, _member_access_statement(last_mem) ) elif last_mem.kind == model.Kind.DYNAMIC or last_mem.dynamic: return 'return cast<{0}*>({1});\n'.format( name, gen_member(last_mem, delimiters) ) else: return gen_member(last_mem) + ';\n' + 'return payload + 1;\n' def gen_main(main, parts): all_names = {mem.name: 'payload' for mem in main} for i, part in enumerate(parts): all_names.update({mem.name: 'part{0}'.format(i + 2) for mem in part}) def get_missing(part_number): part = parts[part_number] names = [mem.name for mem in part] return [(all_names[mem.bound], mem.bound) for mem in part if mem.bound and mem.bound not in names] def gen_missing(part_number): return ''.join(', {0}->{1}'.format(x[0], x[1]) for x in get_missing(part_number)) members = ''.join(gen_member(mem) + ';\n' for mem in main[:-1]) if parts: for i, part in enumerate(parts): members += '{0}::part{1}* part{1} = cast<{0}::part{1}*>({2});\n'.format( struct.name, i + 2, 'swap(part{0}{1})'.format(i + 1, gen_missing(i - 1)) if i else gen_member(main[-1]) ) members += 'return cast<{0}*>(swap(part{1}{2}));\n'.format(struct.name, i + 2, gen_missing(i)) elif main: members += gen_last_member(struct.name, main[-1]) else: members += 'return payload + 1;\n' return ('template <>\n' '{0}* swap<{0}>({0}* payload)\n' '{{\n' '{1}' '}}\n').format(struct.name, _indent(members, 4)) def gen_part(part_number, part): names = [mem.name for mem in part] delimiters = [mem.bound for mem in part if mem.bound and mem.bound not in names] members = ''.join(gen_member(mem, delimiters) + ';\n' for mem in part[:-1]) members += gen_last_member(struct.name + '::part{0}'.format(part_number), part[-1], delimiters) return ('inline {0}::part{1}* swap({0}::part{1}* payload{3})\n' '{{\n' '{2}}}\n').format(struct.name, part_number, _indent(members, 4), ''.join(', size_t {0}'.format(x) for x in delimiters)) main, parts = model.partition(struct.members) return '\n'.join([gen_part(i + 2, part) for i, part in enumerate(parts)] + [gen_main(main, parts)])
def _generate_swap_struct(struct): def gen_member(member, delimiters=[]): if member.array: is_dynamic = member.kind == model.Kind.DYNAMIC swap_mode = 'dynamic' if is_dynamic else 'fixed' if member.bound: bound = member.bound if member.bound not in delimiters: bound = 'payload->' + bound return 'swap_n_{0}({1}, {2})'.format( swap_mode, _member_access_statement(member), bound) elif not member.bound and member.size: return 'swap_n_{0}({1}, {2})'.format( swap_mode, _member_access_statement(member), member.size) else: if member.optional: preamble = 'swap(&payload->has_{0});\nif (payload->has_{0}) '.format( member.name) else: preamble = '' return preamble + 'swap({0})'.format( _member_access_statement(member)) def gen_last_member(name, last_mem, delimiters=[]): if last_mem.kind == model.Kind.UNLIMITED or last_mem.greedy: return 'return cast<{0}*>({1});\n'.format( name, _member_access_statement(last_mem)) elif last_mem.kind == model.Kind.DYNAMIC or last_mem.dynamic: return 'return cast<{0}*>({1});\n'.format( name, gen_member(last_mem, delimiters)) else: return gen_member(last_mem) + ';\n' + 'return payload + 1;\n' def gen_main(main, parts): all_names = {mem.name: 'payload' for mem in main} for i, part in enumerate(parts): all_names.update( {mem.name: 'part{0}'.format(i + 2) for mem in part}) def get_missing(part_number): part = parts[part_number] names = [mem.name for mem in part] return [(all_names[mem.bound], mem.bound) for mem in part if mem.bound and mem.bound not in names] def gen_missing(part_number): return ''.join(', {0}->{1}'.format(x[0], x[1]) for x in get_missing(part_number)) members = ''.join(gen_member(mem) + ';\n' for mem in main[:-1]) if parts: for i, part in enumerate(parts): members += '{0}::part{1}* part{1} = cast<{0}::part{1}*>({2});\n'.format( struct.name, i + 2, 'swap(part{0}{1})'.format(i + 1, gen_missing(i - 1)) if i else gen_member(main[-1])) members += 'return cast<{0}*>(swap(part{1}{2}));\n'.format( struct.name, i + 2, gen_missing(i)) elif main: members += gen_last_member(struct.name, main[-1]) else: members += 'return payload + 1;\n' return ('template <>\n' '{0}* swap<{0}>({0}* payload)\n' '{{\n' '{1}' '}}\n').format(struct.name, _indent(members, 4)) def gen_part(part_number, part): names = [mem.name for mem in part] delimiters = [ mem.bound for mem in part if mem.bound and mem.bound not in names ] members = ''.join( gen_member(mem, delimiters) + ';\n' for mem in part[:-1]) members += gen_last_member( struct.name + '::part{0}'.format(part_number), part[-1], delimiters) return ('inline {0}::part{1}* swap({0}::part{1}* payload{3})\n' '{{\n' '{2}}}\n').format( struct.name, part_number, _indent(members, 4), ''.join(', size_t {0}'.format(x) for x in delimiters)) main, parts = model.partition(struct.members) return '\n'.join([gen_part(i + 2, part) for i, part in enumerate(parts)] + [gen_main(main, parts)])