18157b447Smrg#!/usr/bin/env python3
21c606da7Smrg
31c606da7Smrgimport argparse
41c606da7Smrgimport re
58157b447Smrgimport sys
68157b447Smrgfrom pathlib import Path
71c606da7Smrg
81c606da7Smrg
91c606da7Smrgclass Layout(object):
101c606da7Smrg    def __init__(self, layout, variant=None):
111c606da7Smrg        self.layout = layout
121c606da7Smrg        self.variant = variant
131c606da7Smrg        if '(' in layout:
141c606da7Smrg            assert variant is None
151c606da7Smrg            # parse a layout(variant) string
161c606da7Smrg            match = re.match(r'([^(]+)\(([^)]+)\)', layout)
178157b447Smrg            self.layout = match.groups()[0]
188157b447Smrg            self.variant = match.groups()[1]
191c606da7Smrg
201c606da7Smrg    def __str__(self):
211c606da7Smrg        if self.variant:
221c606da7Smrg            return '{}({})'.format(self.layout, self.variant)
231c606da7Smrg        else:
241c606da7Smrg            return '{}'.format(self.layout)
251c606da7Smrg
261c606da7Smrg
271c606da7Smrgdef read_file(path):
281c606da7Smrg    '''Returns a list of two-layout tuples [(layout1, layout2), ...]'''
291c606da7Smrg
301c606da7Smrg    # This parses both input files, one with two elements, one with four elements,
311c606da7Smrg    # all separated by tabs
321c606da7Smrg    pattern = re.compile(r'([^\t]+)\s+([^\t]+)\s*([^\t]*)\s*([^\t]*)')
331c606da7Smrg
341c606da7Smrg    layouts = []
351c606da7Smrg    for line in open(path):
361c606da7Smrg        match = re.match(pattern, line.strip())
371c606da7Smrg        groups = [g for g in match.groups() if g]  # drop empty groups
381c606da7Smrg        if len(groups) == 2:
391c606da7Smrg            l1 = Layout(groups[0])
401c606da7Smrg            l2 = Layout(groups[1])
411c606da7Smrg        else:
421c606da7Smrg            l1 = Layout(groups[0], groups[1])
431c606da7Smrg            l2 = Layout(groups[2], groups[3])
441c606da7Smrg        layouts.append((l1, l2))
451c606da7Smrg    return layouts
461c606da7Smrg
471c606da7Smrg
481c606da7Smrg# ml_s
491c606da7Smrgdef write_fixed_layout(dest, mappings, write_header):
501c606da7Smrg    if write_header:
511c606da7Smrg        dest.write('! model		layout				=	symbols\n')
521c606da7Smrg    for l1, l2 in mappings:
531c606da7Smrg        dest.write('  *		{}			=	pc+{}\n'.format(l1, l2))
541c606da7Smrg
551c606da7Smrg
561c606da7Smrg# mln_s
571c606da7Smrgdef write_layout_n(dest, mappings, number, write_header):
581c606da7Smrg    if write_header:
591c606da7Smrg        dest.write('! model		layout[{}]	=	symbols\n'.format(number))
601c606da7Smrg
611c606da7Smrg    # symbols is one of
621c606da7Smrg    #   +layout(variant):2 ... where the map-to-layout has a proper variant
631c606da7Smrg    #   +layout%(v[2]):2 ... where the map-to-layout does not have a variant
641c606da7Smrg    # and where the number is 1, we have a base and drop the suffix, i.e.
651c606da7Smrg    # the above becomes
661c606da7Smrg    #   pc+layout(variant)
671c606da7Smrg    #   pc+layout%(v[1])
681c606da7Smrg
691c606da7Smrg    base = 'pc' if number == 1 else ''
701c606da7Smrg    suffix = '' if number == 1 else ':{}'.format(number)
711c606da7Smrg
721c606da7Smrg    for l1, l2 in mappings:
731c606da7Smrg        second_layout = str(l2) if l2.variant else '{}%(v[{}])'.format(l2.layout, number)
741c606da7Smrg        dest.write('  *		{}		=	{}+{}{}\n'.format(l1, base, second_layout, suffix))
751c606da7Smrg
761c606da7Smrg
771c606da7Smrg# mlv_s
781c606da7Smrgdef write_fixed_layout_variant(dest, mappings, write_header):
791c606da7Smrg    if write_header:
801c606da7Smrg        dest.write('! model		layout		variant		=	symbols\n')
811c606da7Smrg    for l1, l2 in mappings:
821c606da7Smrg        dest.write('  *		{}		{}		=	pc+{}\n'.format(l1.layout, l1.variant, l2))
831c606da7Smrg
841c606da7Smrg
851c606da7Smrg# mlnvn_s
861c606da7Smrgdef write_layout_n_variant_n(dest, mappings, number, write_header):
871c606da7Smrg    if write_header:
881c606da7Smrg        dest.write('! model		layout[{}]	variant[{}]	=	symbols\n'.format(number, number))
891c606da7Smrg
901c606da7Smrg    # symbols is
911c606da7Smrg    #   +layout(variant):2
921c606da7Smrg    # and where the number is 1, we have a base and drop the suffix, i.e.
931c606da7Smrg    # the above becomes
941c606da7Smrg    #   pc+layout(variant)
951c606da7Smrg    # This part is only executed for the variantMappings.lst
961c606da7Smrg
971c606da7Smrg    base = 'pc' if number == 1 else ''
981c606da7Smrg    suffix = '' if number == 1 else ':{}'.format(number)
991c606da7Smrg
1001c606da7Smrg    for l1, l2 in mappings:
1011c606da7Smrg        second_layout = str(l2) if l2.variant else '{}%(v[{}])'.format(l2.layout, number)
1021c606da7Smrg        dest.write('  *		{}		{}	=	{}+{}{}\n'.format(l1.layout, l1.variant, base, second_layout, suffix))
1031c606da7Smrg
1041c606da7Smrg
1051c606da7Smrgdef map_variant(dest, files, want='mls', number=None):
1068157b447Smrg    if number == 0:
1078157b447Smrg        number = None
1088157b447Smrg
1091c606da7Smrg    for idx, f in enumerate(files):
1101c606da7Smrg        write_header = idx == 0
1111c606da7Smrg
1121c606da7Smrg        mappings = read_file(f)
1131c606da7Smrg        if want == 'mls':
1141c606da7Smrg            if number is None:
1151c606da7Smrg                write_fixed_layout(dest, mappings, write_header)
1161c606da7Smrg            else:
1171c606da7Smrg                write_layout_n(dest, mappings, number, write_header)
1181c606da7Smrg        elif want == 'mlvs':
1191c606da7Smrg            if number is None:
1201c606da7Smrg                write_fixed_layout_variant(dest, mappings, write_header)
1211c606da7Smrg            else:
1221c606da7Smrg                write_layout_n_variant_n(dest, mappings, number, write_header)
1231c606da7Smrg        else:
1241c606da7Smrg            raise NotImplementedError()
1251c606da7Smrg
1261c606da7Smrg
1271c606da7Smrgif __name__ == '__main__':
1281c606da7Smrg    parser = argparse.ArgumentParser('variant mapping script')
1291c606da7Smrg    parser.add_argument('--want', type=str,
1301c606da7Smrg                        choices=['mls', 'mlvs'])
1311c606da7Smrg    parser.add_argument('--number', type=int, default=None)
1321c606da7Smrg
1331c606da7Smrg    parser.add_argument('dest', type=str)
1341c606da7Smrg    parser.add_argument('files', nargs='+', type=str)
1351c606da7Smrg    ns = parser.parse_args()
1361c606da7Smrg
1378157b447Smrg    dest = None
1388157b447Smrg    if ns.dest == '-':
1398157b447Smrg        dest = sys.stdout
1408157b447Smrg
1418157b447Smrg    with dest or open(ns.dest, 'w') as fd:
1421c606da7Smrg        map_variant(fd, ns.files, ns.want, ns.number)
143