blob: b1907f1992a20c9b1d6f262c8c4f21d3b0f85515 [file] [edit]
#!/usr/bin/env python3
# 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.
"""Main driver program for the Emboss compiler."""
import argparse
import os
import sys
def _parse_args(argv):
parser = argparse.ArgumentParser(description="Emboss compiler")
parser.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'.",
)
parser.add_argument(
"--import-dir",
"-I",
dest="import_dirs",
action="append",
default=["."],
help="""A directory to use when searching for imported embs. If no
import-dirs are specified, the current directory will be used.""",
)
parser.add_argument(
"--generate",
choices=["cc", "rust"],
default="cc",
help="Which back end to use. Currently C++ ('cc') and Rust ('rust') are supported.",
)
parser.add_argument(
"--output-path",
nargs=1,
default=".",
help="Prefix path to use for the generated output file. Defaults to '.'",
)
parser.add_argument(
"--output-file",
nargs=1,
help="""File name to be used for the generated output file. Defaults to
input_file suffixed by '.h'""",
)
parser.add_argument(
"--cc-enum-traits",
action=argparse.BooleanOptionalAction,
default=True,
help="Controls generation of EnumTraits by the C++ backend",
)
parser.add_argument(
"--no-experimental-warning",
action="store_true",
help="Suppress experimental warnings",
)
parser.add_argument("input_file", type=str, nargs=1, help=".emb file to compile.")
return parser.parse_args(argv[1:])
def _generate_code_and_log_errors(ir, flags):
match flags.generate:
case "rust":
from compiler.back_end.experimental.rust import (
emboss_codegen_rust,
) # pylint:disable=import-outside-toplevel
return emboss_codegen_rust.generate_code_and_log_errors(
ir, flags.color_output, not flags.no_experimental_warning
)
case "cc":
from compiler.back_end.cpp import (
emboss_codegen_cpp,
header_generator,
) # pylint:disable=import-outside-toplevel
config = header_generator.Config(include_enum_traits=flags.cc_enum_traits)
return emboss_codegen_cpp.generate_headers_and_log_errors(
ir, flags.color_output, config
)
case _:
raise ValueError(f"Unknown generation language: {flags.generate}")
def _default_file_suffix(generate_lang):
match generate_lang:
case "rust":
return ".rs"
case "cc":
return ".h"
case _:
raise ValueError(f"Unknown generation language: {generate_lang}")
def _format_code(code, generate_lang):
match generate_lang:
case "rust":
return code
case "cc":
from compiler.back_end.cpp import (
emboss_codegen_cpp,
) # pylint:disable=import-outside-toplevel
return emboss_codegen_cpp.format_header(code)
case _:
raise ValueError(f"Unknown generation language: {generate_lang}")
def main(argv):
flags = _parse_args(argv)
base_path = os.path.dirname(__file__) or "."
sys.path.append(base_path)
from compiler.front_end import ( # pylint:disable=import-outside-toplevel
emboss_front_end,
)
ir, _, errors = emboss_front_end.parse_and_log_errors(
flags.input_file[0], flags.import_dirs, flags.color_output
)
if errors:
return 1
code, errors = _generate_code_and_log_errors(ir, flags)
if errors:
return 1
if flags.output_file:
output_file = flags.output_file[0]
else:
output_file = flags.input_file[0] + _default_file_suffix(flags.generate)
output_filepath = os.path.join(flags.output_path[0], output_file)
os.makedirs(os.path.dirname(output_filepath), exist_ok=True)
with open(output_filepath, "w") as output:
output.write(_format_code(code, flags.generate))
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))