xref: /aosp_15_r20/external/emboss/compiler/front_end/format.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1*99e0aae7SDavid Rees# Copyright 2019 Google LLC
2*99e0aae7SDavid Rees#
3*99e0aae7SDavid Rees# Licensed under the Apache License, Version 2.0 (the "License");
4*99e0aae7SDavid Rees# you may not use this file except in compliance with the License.
5*99e0aae7SDavid Rees# You may obtain a copy of the License at
6*99e0aae7SDavid Rees#
7*99e0aae7SDavid Rees#     https://www.apache.org/licenses/LICENSE-2.0
8*99e0aae7SDavid Rees#
9*99e0aae7SDavid Rees# Unless required by applicable law or agreed to in writing, software
10*99e0aae7SDavid Rees# distributed under the License is distributed on an "AS IS" BASIS,
11*99e0aae7SDavid Rees# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*99e0aae7SDavid Rees# See the License for the specific language governing permissions and
13*99e0aae7SDavid Rees# limitations under the License.
14*99e0aae7SDavid Rees
15*99e0aae7SDavid Rees"""Formatter for Emboss source files.
16*99e0aae7SDavid Rees
17*99e0aae7SDavid ReesThis program formats an Emboss source file given on the command line.
18*99e0aae7SDavid Rees"""
19*99e0aae7SDavid Rees
20*99e0aae7SDavid Reesfrom __future__ import absolute_import
21*99e0aae7SDavid Reesfrom __future__ import print_function
22*99e0aae7SDavid Rees
23*99e0aae7SDavid Reesimport argparse
24*99e0aae7SDavid Reesimport os
25*99e0aae7SDavid Reesimport sys
26*99e0aae7SDavid Rees
27*99e0aae7SDavid Reesfrom compiler.front_end import format_emb
28*99e0aae7SDavid Reesfrom compiler.front_end import parser
29*99e0aae7SDavid Reesfrom compiler.front_end import tokenizer
30*99e0aae7SDavid Reesfrom compiler.util import error
31*99e0aae7SDavid Rees
32*99e0aae7SDavid Rees
33*99e0aae7SDavid Reesdef _parse_command_line(argv):
34*99e0aae7SDavid Rees  """Parses the given command-line arguments."""
35*99e0aae7SDavid Rees  argparser = argparse.ArgumentParser(description='Emboss compiler front end.',
36*99e0aae7SDavid Rees                                      prog=argv[0])
37*99e0aae7SDavid Rees  argparser.add_argument('input_file',
38*99e0aae7SDavid Rees                         type=str,
39*99e0aae7SDavid Rees                         nargs='+',
40*99e0aae7SDavid Rees                         help='.emb file to compile.')
41*99e0aae7SDavid Rees  argparser.add_argument('--no-check-result',
42*99e0aae7SDavid Rees                         default=True,
43*99e0aae7SDavid Rees                         action='store_false',
44*99e0aae7SDavid Rees                         dest='check_result',
45*99e0aae7SDavid Rees                         help='Verify that the resulting formatted text '
46*99e0aae7SDavid Rees                         'contains only whitespace changes.')
47*99e0aae7SDavid Rees  argparser.add_argument('--debug-show-line-types',
48*99e0aae7SDavid Rees                         default=False,
49*99e0aae7SDavid Rees                         help='Show the computed type of each line.')
50*99e0aae7SDavid Rees  argparser.add_argument('--no-edit-in-place',
51*99e0aae7SDavid Rees                         default=True,
52*99e0aae7SDavid Rees                         action='store_false',
53*99e0aae7SDavid Rees                         dest='edit_in_place',
54*99e0aae7SDavid Rees                         help='Write the formatted text back to the input '
55*99e0aae7SDavid Rees                              'file.')
56*99e0aae7SDavid Rees  argparser.add_argument('--indent',
57*99e0aae7SDavid Rees                         type=int,
58*99e0aae7SDavid Rees                         default=2,
59*99e0aae7SDavid Rees                         help='Number of spaces to use for each level of '
60*99e0aae7SDavid Rees                         'indentation.')
61*99e0aae7SDavid Rees  argparser.add_argument('--color-output',
62*99e0aae7SDavid Rees                         default='if-tty',
63*99e0aae7SDavid Rees                         choices=['always', 'never', 'if-tty', 'auto'],
64*99e0aae7SDavid Rees                         help="Print error messages using color.  'auto' is a "
65*99e0aae7SDavid Rees                         "synonym for 'if-tty'.")
66*99e0aae7SDavid Rees  return argparser.parse_args(argv[1:])
67*99e0aae7SDavid Rees
68*99e0aae7SDavid Rees
69*99e0aae7SDavid Reesdef _print_errors(errors, source_codes, flags):
70*99e0aae7SDavid Rees  use_color = (flags.color_output == 'always' or
71*99e0aae7SDavid Rees               (flags.color_output in ('auto', 'if-tty') and
72*99e0aae7SDavid Rees                os.isatty(sys.stderr.fileno())))
73*99e0aae7SDavid Rees  print(error.format_errors(errors, source_codes, use_color), file=sys.stderr)
74*99e0aae7SDavid Rees
75*99e0aae7SDavid Rees
76*99e0aae7SDavid Reesdef main(argv=()):
77*99e0aae7SDavid Rees  flags = _parse_command_line(argv)
78*99e0aae7SDavid Rees
79*99e0aae7SDavid Rees  if not flags.edit_in_place and len(flags.input_file) > 1:
80*99e0aae7SDavid Rees    print('Multiple files may only be formatted without --no-edit-in-place.',
81*99e0aae7SDavid Rees          file=sys.stderr)
82*99e0aae7SDavid Rees    return 1
83*99e0aae7SDavid Rees
84*99e0aae7SDavid Rees  if flags.edit_in_place and flags.debug_show_line_types:
85*99e0aae7SDavid Rees    print('The flag --debug-show-line-types requires --no-edit-in-place.',
86*99e0aae7SDavid Rees          file=sys.stderr)
87*99e0aae7SDavid Rees    return 1
88*99e0aae7SDavid Rees
89*99e0aae7SDavid Rees  for file_name in flags.input_file:
90*99e0aae7SDavid Rees    with open(file_name) as f:
91*99e0aae7SDavid Rees      source_code = f.read()
92*99e0aae7SDavid Rees
93*99e0aae7SDavid Rees    tokens, errors = tokenizer.tokenize(source_code, file_name)
94*99e0aae7SDavid Rees    if errors:
95*99e0aae7SDavid Rees      _print_errors(errors, {file_name: source_code}, flags)
96*99e0aae7SDavid Rees      continue
97*99e0aae7SDavid Rees
98*99e0aae7SDavid Rees    parse_result = parser.parse_module(tokens)
99*99e0aae7SDavid Rees    if parse_result.error:
100*99e0aae7SDavid Rees      _print_errors(
101*99e0aae7SDavid Rees          [error.make_error_from_parse_error(file_name, parse_result.error)],
102*99e0aae7SDavid Rees          {file_name: source_code},
103*99e0aae7SDavid Rees          flags)
104*99e0aae7SDavid Rees      continue
105*99e0aae7SDavid Rees
106*99e0aae7SDavid Rees    formatted_text = format_emb.format_emboss_parse_tree(
107*99e0aae7SDavid Rees        parse_result.parse_tree,
108*99e0aae7SDavid Rees        format_emb.Config(show_line_types=flags.debug_show_line_types,
109*99e0aae7SDavid Rees                          indent_width=flags.indent))
110*99e0aae7SDavid Rees
111*99e0aae7SDavid Rees    if flags.check_result and not flags.debug_show_line_types:
112*99e0aae7SDavid Rees      errors = format_emb.sanity_check_format_result(formatted_text,
113*99e0aae7SDavid Rees                                                     source_code)
114*99e0aae7SDavid Rees      if errors:
115*99e0aae7SDavid Rees        for e in errors:
116*99e0aae7SDavid Rees          print(e, file=sys.stderr)
117*99e0aae7SDavid Rees        continue
118*99e0aae7SDavid Rees
119*99e0aae7SDavid Rees    if flags.edit_in_place:
120*99e0aae7SDavid Rees      with open(file_name, 'w') as f:
121*99e0aae7SDavid Rees        f.write(formatted_text)
122*99e0aae7SDavid Rees    else:
123*99e0aae7SDavid Rees      sys.stdout.write(formatted_text)
124*99e0aae7SDavid Rees
125*99e0aae7SDavid Rees  return 0
126*99e0aae7SDavid Rees
127*99e0aae7SDavid Rees
128*99e0aae7SDavid Reesif __name__ == '__main__':
129*99e0aae7SDavid Rees  sys.exit(main(sys.argv))
130