# Copyright 2019 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Formatter for Emboss source files. This program formats an Emboss source file given on the command line. """ from __future__ import absolute_import from __future__ import print_function import argparse import os import sys from compiler.front_end import format_emb from compiler.front_end import parser from compiler.front_end import tokenizer from compiler.util import error def _parse_command_line(argv): """Parses the given command-line arguments.""" argparser = argparse.ArgumentParser(description='Emboss compiler front end.', prog=argv[0]) argparser.add_argument('input_file', type=str, nargs='+', help='.emb file to compile.') argparser.add_argument('--no-check-result', default=True, action='store_false', dest='check_result', help='Verify that the resulting formatted text ' 'contains only whitespace changes.') argparser.add_argument('--debug-show-line-types', default=False, help='Show the computed type of each line.') argparser.add_argument('--no-edit-in-place', default=True, action='store_false', dest='edit_in_place', help='Write the formatted text back to the input ' 'file.') argparser.add_argument('--indent', type=int, default=2, help='Number of spaces to use for each level of ' 'indentation.') argparser.add_argument('--color-output', default='if-tty', choices=['always', 'never', 'if-tty', 'auto'], help="Print error messages using color. 'auto' is a " "synonym for 'if-tty'.") return argparser.parse_args(argv[1:]) def _print_errors(errors, source_codes, flags): use_color = (flags.color_output == 'always' or (flags.color_output in ('auto', 'if-tty') and os.isatty(sys.stderr.fileno()))) print(error.format_errors(errors, source_codes, use_color), file=sys.stderr) def main(argv=()): flags = _parse_command_line(argv) if not flags.edit_in_place and len(flags.input_file) > 1: print('Multiple files may only be formatted without --no-edit-in-place.', file=sys.stderr) return 1 if flags.edit_in_place and flags.debug_show_line_types: print('The flag --debug-show-line-types requires --no-edit-in-place.', file=sys.stderr) return 1 for file_name in flags.input_file: with open(file_name) as f: source_code = f.read() tokens, errors = tokenizer.tokenize(source_code, file_name) if errors: _print_errors(errors, {file_name: source_code}, flags) continue parse_result = parser.parse_module(tokens) if parse_result.error: _print_errors( [error.make_error_from_parse_error(file_name, parse_result.error)], {file_name: source_code}, flags) continue formatted_text = format_emb.format_emboss_parse_tree( parse_result.parse_tree, format_emb.Config(show_line_types=flags.debug_show_line_types, indent_width=flags.indent)) if flags.check_result and not flags.debug_show_line_types: errors = format_emb.sanity_check_format_result(formatted_text, source_code) if errors: for e in errors: print(e, file=sys.stderr) continue if flags.edit_in_place: with open(file_name, 'w') as f: f.write(formatted_text) else: sys.stdout.write(formatted_text) return 0 if __name__ == '__main__': sys.exit(main(sys.argv))