blob: bcd3b18bd9a8914ae04acb886590f2f2edf05a0c [file] [log] [blame]
#!/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