blob: c0f09bc11611132eaad425914d79231dff8ac7bd [file] [log] [blame]
#!/usr/bin/env fuchsia-vendored-python
# 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