2 """Update Options.td for the flags changes in https://reviews.llvm.org/Dxyz
4 This script translates Options.td from using Flags to control option visibility
5 to using Vis instead. It is meant to be idempotent and usable to help update
6 downstream forks if they have their own changes to Options.td.
10 % update_options_td_flags.py path/to/Options.td > Options.td.new
11 % mv Options.td.new path/to/Options.td
14 This script will be removed after the next LLVM release.
23 def rewrite_option_flags(input_file
, output_file
):
24 for src_line
in input_file
:
25 for dst_line
in process_line(src_line
):
26 output_file
.write(dst_line
)
28 def process_line(line
):
29 # We only deal with one thing per line. If multiple things can be
30 # on the same line (like NegFlag and PosFlag), please preprocess
32 m
= re
.search(r
'((NegFlag|PosFlag)<[A-Za-z]+, |BothFlags<)'
33 r
'\[([A-Za-z0-9, ]+)\](, \[ClangOption\]|(?=>))', line
)
35 return process_boolflags(m
.group(3), line
[:m
.end(1)], line
[m
.end():])
36 m
= re
.search(r
'\bFlags<\[([A-Za-z0-9, ]*)\]>', line
)
38 return process_flags(m
.group(1), line
[:m
.start()], line
[m
.end():])
39 m
= re
.search(r
'let Flags = \[([A-Za-z0-9, ]*)\]', line
)
41 return process_letflags(m
.group(1), line
[:m
.start(1)], line
[m
.end():])
45 def process_boolflags(flag_group
, prefix
, suffix
):
46 flags
= [f
.strip() for f
in flag_group
.split(',')] if flag_group
else []
48 return f
'{prefix}[], [ClangOption]{suffix}'
50 flags_to_keep
, vis_mods
= translate_flags(flags
)
51 flag_text
= f
'[{", ".join(flags_to_keep)}]'
52 vis_text
= f
'[{", ".join(vis_mods)}]'
53 new_text
= ', '.join([flag_text
, vis_text
])
55 if prefix
.startswith('Both'):
56 indent
= ' ' * len(prefix
)
58 indent
= ' ' * (len(prefix
) - len(prefix
.lstrip()) + len('XyzFlag<'))
60 return get_edited_lines(prefix
, new_text
, suffix
, indent
=indent
)
62 def process_flags(flag_group
, prefix
, suffix
):
63 flags
= [f
.strip() for f
in flag_group
.split(',')]
65 flags_to_keep
, vis_mods
= translate_flags(flags
)
70 flag_text
= f
'Flags<[{", ".join(flags_to_keep)}]>'
74 vis_text
= f
'Visibility<[{", ".join(vis_mods)}]>'
76 return get_edited_lines(prefix
, flag_text
, vis_text
, suffix
)
78 def process_letflags(flag_group
, prefix
, suffix
):
79 is_end_comment
= prefix
.startswith('} //')
80 if not is_end_comment
and not prefix
.startswith('let'):
81 raise AssertionError(f
'Unusual let block: {prefix}')
83 flags
= [f
.strip() for f
in flag_group
.split(',')]
85 flags_to_keep
, vis_mods
= translate_flags(flags
)
89 lines
+= [f
'let Flags = [{", ".join(flags_to_keep)}]']
91 lines
+= [f
'let Visibility = [{", ".join(vis_mods)}]']
94 lines
= list(reversed([f
'}} // {l}\n' for l
in lines
]))
96 lines
= [f
'{l} in {{\n' for l
in lines
]
99 def get_edited_lines(prefix
, *fragments
, indent
=' '):
102 for fragment
in fragments
:
103 if fragment
and len(current
) + len(fragment
) > 80:
104 # Make a minimal attempt at reasonable line lengths
105 if fragment
.startswith(',') or fragment
.startswith(';'):
106 # Avoid wrapping the , or ; to the new line
107 current
+= fragment
[0]
108 fragment
= fragment
[1:].lstrip()
109 out_lines
+= [current
.rstrip() + '\n']
110 current
= max(' ' * (len(current
) - len(current
.lstrip())), indent
)
114 out_lines
+= [current
]
117 def translate_flags(flags
):
134 'CoreOption': ['ClangOption', 'CLOption', 'DXCOption'],
135 'CLOption': ['CLOption'],
136 'CC1Option': ['ClangOption', 'CC1Option'],
137 'CC1AsOption': ['ClangOption', 'CC1AsOption'],
138 'FlangOption': ['ClangOption', 'FlangOption'],
139 'FC1Option': ['ClangOption', 'FC1Option'],
140 'DXCOption': ['DXCOption'],
141 'CLDXCOption': ['CLOption', 'DXCOption'],
145 has_no_driver
= False
146 has_flang_only
= False
148 if flag
in driver_flags
or flag
in custom_flags
:
150 elif flag
in flag_to_vis
:
151 vis_mods
+= flag_to_vis
[flag
]
152 elif flag
== 'NoDriverOption':
154 elif flag
== 'FlangOnlyOption':
155 has_flang_only
= True
157 raise AssertionError(f
'Unknown flag: {flag}')
161 if vis
in new_vis_mods
:
163 if has_no_driver
and vis
== 'ClangOption':
165 if has_flang_only
and vis
== 'ClangOption':
167 new_vis_mods
+= [vis
]
169 return new_flags
, new_vis_mods
172 parser
= argparse
.ArgumentParser()
173 parser
.add_argument('src', nargs
='?', default
='-',
174 type=argparse
.FileType('r', encoding
='UTF-8'))
175 parser
.add_argument('-o', dest
='dst', default
='-',
176 type=argparse
.FileType('w', encoding
='UTF-8'))
178 args
= parser
.parse_args()
179 rewrite_option_flags(args
.src
, args
.dst
)
181 if __name__
== '__main__':