| # 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)) |