1#!/usr/bin/env python3 2 3import argparse 4import re 5import sys 6from pathlib import Path 7 8 9class Layout(object): 10 def __init__(self, layout, variant=None): 11 self.layout = layout 12 self.variant = variant 13 if '(' in layout: 14 assert variant is None 15 # parse a layout(variant) string 16 match = re.match(r'([^(]+)\(([^)]+)\)', layout) 17 self.layout = match.groups()[0] 18 self.variant = match.groups()[1] 19 20 def __str__(self): 21 if self.variant: 22 return '{}({})'.format(self.layout, self.variant) 23 else: 24 return '{}'.format(self.layout) 25 26 27def read_file(path): 28 '''Returns a list of two-layout tuples [(layout1, layout2), ...]''' 29 30 # This parses both input files, one with two elements, one with four elements, 31 # all separated by tabs 32 pattern = re.compile(r'([^\t]+)\s+([^\t]+)\s*([^\t]*)\s*([^\t]*)') 33 34 layouts = [] 35 for line in open(path): 36 match = re.match(pattern, line.strip()) 37 groups = [g for g in match.groups() if g] # drop empty groups 38 if len(groups) == 2: 39 l1 = Layout(groups[0]) 40 l2 = Layout(groups[1]) 41 else: 42 l1 = Layout(groups[0], groups[1]) 43 l2 = Layout(groups[2], groups[3]) 44 layouts.append((l1, l2)) 45 return layouts 46 47 48# ml_s 49def write_fixed_layout(dest, mappings, write_header): 50 if write_header: 51 dest.write('! model layout = symbols\n') 52 for l1, l2 in mappings: 53 dest.write(' * {} = pc+{}\n'.format(l1, l2)) 54 55 56# mln_s 57def write_layout_n(dest, mappings, number, write_header): 58 if write_header: 59 dest.write('! model layout[{}] = symbols\n'.format(number)) 60 61 # symbols is one of 62 # +layout(variant):2 ... where the map-to-layout has a proper variant 63 # +layout%(v[2]):2 ... where the map-to-layout does not have a variant 64 # and where the number is 1, we have a base and drop the suffix, i.e. 65 # the above becomes 66 # pc+layout(variant) 67 # pc+layout%(v[1]) 68 69 base = 'pc' if number == 1 else '' 70 suffix = '' if number == 1 else ':{}'.format(number) 71 72 for l1, l2 in mappings: 73 second_layout = str(l2) if l2.variant else '{}%(v[{}])'.format(l2.layout, number) 74 dest.write(' * {} = {}+{}{}\n'.format(l1, base, second_layout, suffix)) 75 76 77# mlv_s 78def write_fixed_layout_variant(dest, mappings, write_header): 79 if write_header: 80 dest.write('! model layout variant = symbols\n') 81 for l1, l2 in mappings: 82 dest.write(' * {} {} = pc+{}\n'.format(l1.layout, l1.variant, l2)) 83 84 85# mlnvn_s 86def write_layout_n_variant_n(dest, mappings, number, write_header): 87 if write_header: 88 dest.write('! model layout[{}] variant[{}] = symbols\n'.format(number, number)) 89 90 # symbols is 91 # +layout(variant):2 92 # and where the number is 1, we have a base and drop the suffix, i.e. 93 # the above becomes 94 # pc+layout(variant) 95 # This part is only executed for the variantMappings.lst 96 97 base = 'pc' if number == 1 else '' 98 suffix = '' if number == 1 else ':{}'.format(number) 99 100 for l1, l2 in mappings: 101 second_layout = str(l2) if l2.variant else '{}%(v[{}])'.format(l2.layout, number) 102 dest.write(' * {} {} = {}+{}{}\n'.format(l1.layout, l1.variant, base, second_layout, suffix)) 103 104 105def map_variant(dest, files, want='mls', number=None): 106 if number == 0: 107 number = None 108 109 for idx, f in enumerate(files): 110 write_header = idx == 0 111 112 mappings = read_file(f) 113 if want == 'mls': 114 if number is None: 115 write_fixed_layout(dest, mappings, write_header) 116 else: 117 write_layout_n(dest, mappings, number, write_header) 118 elif want == 'mlvs': 119 if number is None: 120 write_fixed_layout_variant(dest, mappings, write_header) 121 else: 122 write_layout_n_variant_n(dest, mappings, number, write_header) 123 else: 124 raise NotImplementedError() 125 126 127if __name__ == '__main__': 128 parser = argparse.ArgumentParser('variant mapping script') 129 parser.add_argument('--want', type=str, 130 choices=['mls', 'mlvs']) 131 parser.add_argument('--number', type=int, default=None) 132 133 parser.add_argument('dest', type=str) 134 parser.add_argument('files', nargs='+', type=str) 135 ns = parser.parse_args() 136 137 dest = None 138 if ns.dest == '-': 139 dest = sys.stdout 140 141 with dest or open(ns.dest, 'w') as fd: 142 map_variant(fd, ns.files, ns.want, ns.number) 143