| #!/usr/bin/python3 |
| # Copyright 2020 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ |
| example: |
| find . \ |
| -path ./out -prune -o \ |
| -path ./garnet/public/lib/fidl/fuzz/input_corpus -prune -o \ |
| -path ./prebuilt -prune -o \ |
| -type f \ |
| -name \*.fidl -print0 \ |
| | xargs -0 tools/fidl/scripts/format_unions.py |
| """ |
| |
| import sys |
| |
| KW_REPLACEMENTS = [ |
| ('xunion', 'flexible union'), |
| ('union', 'strict union'), |
| ('strict xunion', 'strict union'), |
| # ('strict union', 'union') |
| ] |
| |
| |
| def starts_with_oneof(s, prefixes): |
| return any(s.startswith(p) for p in prefixes) |
| |
| |
| def format_file(path, in_place, format_lines): |
| with open(path, 'r+') as f: |
| result = format_lines(f) |
| |
| if in_place: |
| with open(path, 'w') as f: |
| f.writelines(result) |
| else: |
| print(''.join(result)) |
| |
| |
| def has_explicit_xunion(path): |
| with open(path, 'r') as f: |
| in_union = False |
| for line in f: |
| if starts_with_oneof(line, ['xunion ', 'strict xunion ']): |
| in_union = True |
| elif in_union and line.startswith('}'): |
| in_union = False |
| elif in_union and is_explicit(line.split()): |
| return True |
| return False |
| |
| |
| def purge_xunion(in_lines): |
| out_lines = [] |
| for line in in_lines: |
| for before, after in KW_REPLACEMENTS: |
| if line.startswith(before): |
| without_keyword = slice(len(before), None) |
| updated = after + line[without_keyword] |
| out_lines.append(updated) |
| break |
| else: |
| out_lines.append(line) |
| return out_lines |
| |
| |
| def add_explicit_ordinals(in_lines): |
| out_lines = [] |
| current_union_lines = [] |
| in_union = False |
| for line in in_lines: |
| if starts_with_oneof(line, ['union ', 'xunion ', 'strict xunion ']): |
| in_union = True |
| out_lines.append(line) |
| elif line.startswith('}') and in_union: |
| out_lines += format_union_member_lines(current_union_lines) |
| out_lines.append(line) |
| current_union_lines = [] |
| in_union = False |
| elif in_union: |
| current_union_lines.append(line) |
| else: |
| out_lines.append(line) |
| return out_lines |
| |
| |
| def format_union_member_lines(lines): |
| out_lines = [] |
| ordinal_width = len( |
| str(len([l for l in lines if is_union_field_line(l.split())]))) |
| index = 1 |
| for line in lines: |
| tokens = line.split() |
| if not is_union_field_line(tokens): |
| out_lines.append(line) |
| elif is_explicit(tokens): |
| out_lines.append(line) |
| else: # implicit, update to be explicit |
| extra_spaces = (ordinal_width - len(str(index))) * ' ' |
| indent = (len(line) - len(line.lstrip())) * ' ' |
| out_lines.append( |
| '{0}{1}{2}: {3}'.format( |
| indent, extra_spaces, index, line.lstrip())) |
| index += 1 |
| return out_lines |
| |
| |
| def is_union_field_line(tokens): |
| return not ( |
| not tokens or tokens[0].startswith('//') or tokens[0].startswith('[')) |
| |
| |
| def is_explicit(tokens): |
| return tokens and tokens[0].endswith(':') and tokens[0][:-1].isnumeric() |
| |
| |
| def test(): |
| explicit_lines = [ |
| ' 1: uint8 unused1;', |
| ' 2: uint8 unused2;', |
| ' 3: array<uint8>:6 variant;', |
| ] |
| print(format_union_member_lines(explicit_lines)) |
| |
| implicit_lines = [ |
| ' uint32 before;', |
| ' UnionSize12Alignment4 union;', |
| ' uint32 after;', |
| ] |
| print(format_union_member_lines(implicit_lines)) |
| |
| many_lines = [ |
| ' uint32 before;', |
| ' UnionSize12Alignment4 union;', |
| ' uint32 after;', |
| ' uint32 before;', |
| ' UnionSize12Alignment4 union;', |
| ' uint32 after;', |
| ' uint32 before;', |
| ' UnionSize12Alignment4 union;', |
| ' uint32 after;', |
| ' uint32 before;', |
| ' UnionSize12Alignment4 union;', |
| ' uint32 after;', |
| ] |
| print(format_union_member_lines(many_lines)) |
| |
| # doesn't currently work |
| attribute_inline = [ |
| ' [Selector = "v2"] Foo foo;', |
| ] |
| print(format_union_member_lines(attribute_inline)) |
| |
| |
| if __name__ == '__main__': |
| for filename in sys.argv[1:]: |
| try: |
| format_file(filename, in_place=True, format_lines=purge_xunion) |
| # if (has_explicit_xunion(filename)): |
| # print(filename) |
| except: |
| print('error in file: {0}'.format(filename)) |
| raise |