Merge pull request #123 from EricRahm/remove_subproc

Call parsing and generation functions directly in `embossc`
diff --git a/compiler/back_end/cpp/emboss_codegen_cpp.py b/compiler/back_end/cpp/emboss_codegen_cpp.py
index 77bcb84..ed5e66e 100644
--- a/compiler/back_end/cpp/emboss_codegen_cpp.py
+++ b/compiler/back_end/cpp/emboss_codegen_cpp.py
@@ -48,16 +48,30 @@
   return parser.parse_args(argv[1:])
 
 
-def _show_errors(errors, ir, flags):
+def _show_errors(errors, ir, color_output):
   """Prints errors with source code snippets."""
   source_codes = {}
   for module in ir.module:
     source_codes[module.source_file_name] = module.source_text
-  use_color = (flags.color_output == "always" or
-               (flags.color_output in ("auto", "if_tty") and
+  use_color = (color_output == "always" or
+               (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 generate_headers_and_log_errors(ir, color_output):
+  """Generates a C++ header and logs any errors.
+
+  Arguments:
+    ir: EmbossIr of the module.
+    color_output: "always", "never", "if_tty", "auto"
+
+  Returns:
+    A tuple of (header, errors)
+  """
+  header, errors = header_generator.generate_header(ir)
+  if errors:
+    _show_errors(errors, ir, color_output)
+  return (header, errors)
 
 def main(flags):
   if flags.input_file:
@@ -65,9 +79,8 @@
       ir = ir_pb2.EmbossIr.from_json(f.read())
   else:
     ir = ir_pb2.EmbossIr.from_json(sys.stdin.read())
-  header, errors = header_generator.generate_header(ir)
+  header, errors = generate_headers_and_log_errors(ir, flags.color_output)
   if errors:
-    _show_errors(errors, ir, flags)
     return 1
   if flags.output_file:
     with open(flags.output_file, "w") as f:
diff --git a/compiler/front_end/emboss_front_end.py b/compiler/front_end/emboss_front_end.py
index 7df6782..6232a40 100644
--- a/compiler/front_end/emboss_front_end.py
+++ b/compiler/front_end/emboss_front_end.py
@@ -86,14 +86,14 @@
   return parser.parse_args(argv[1:])
 
 
-def _show_errors(errors, ir, flags):
+def _show_errors(errors, ir, color_output):
   """Prints errors with source code snippets."""
   source_codes = {}
   if ir:
     for module in ir.module:
       source_codes[module.source_file_name] = module.source_text
-  use_color = (flags.color_output == "always" or
-               (flags.color_output in ("auto", "if_tty") and
+  use_color = (color_output == "always" or
+               (color_output in ("auto", "if_tty") and
                 os.isatty(sys.stderr.fileno())))
   print(error.format_errors(errors, source_codes, use_color), file=sys.stderr)
 
@@ -128,12 +128,28 @@
 
   return _find_and_read
 
+def parse_and_log_errors(input_file, import_dirs, color_output):
+  """Fully parses an .emb and logs any errors.
+
+  Arguments:
+    input_file: The path of the module source file.
+    import_dirs: Directories to search for imported dependencies.
+    color_output: Used when logging errors: "always", "never", "if_tty", "auto"
+
+  Returns:
+    (ir, debug_info, errors)
+  """
+  ir, debug_info, errors = glue.parse_emboss_file(
+      input_file, _find_in_dirs_and_read(import_dirs))
+  if errors:
+    _show_errors(errors, ir, color_output)
+
+  return (ir, debug_info, errors)
 
 def main(flags):
-  ir, debug_info, errors = glue.parse_emboss_file(
-      flags.input_file[0], _find_in_dirs_and_read(flags.import_dirs))
+  ir, debug_info, errors = parse_and_log_errors(
+    flags.input_file[0], flags.import_dirs, flags.color_output)
   if errors:
-    _show_errors(errors, ir, flags)
     return 1
   main_module_debug_info = debug_info.modules[flags.input_file[0]]
   if flags.debug_show_tokenization:
diff --git a/embossc b/embossc
index cee92d8..0dac79f 100755
--- a/embossc
+++ b/embossc
@@ -18,10 +18,8 @@
 
 import argparse
 import os
-import subprocess
 import sys
 
-
 def _parse_args(argv):
   parser = argparse.ArgumentParser(description="Emboss compiler")
   parser.add_argument("--color-output",
@@ -59,48 +57,28 @@
 
 
 def main(argv):
-
   flags = _parse_args(argv)
   base_path = os.path.dirname(__file__) or "."
-  subprocess_environment = os.environ.copy()
+  sys.path.append(base_path)
 
-  if subprocess_environment.get("PYTHONPATH"):
-    subprocess_environment["PYTHONPATH"] = (
-      base_path + ":" + subprocess_environment.get("PYTHONPATH"))
-  else:
-    subprocess_environment["PYTHONPATH"] = base_path
-
-  front_end_args = [
-      sys.executable,
-      os.path.join(base_path, "compiler", "front_end", "emboss_front_end.py"),
-      "--output-ir-to-stdout",
-      "--color-output", flags.color_output,
-  ]
-
-  for import_dir in flags.import_dirs:
-    front_end_args.extend(["--import-dir", import_dir])
-
-  front_end_args.append(flags.input_file[0])
-  front_end_status = subprocess.run(front_end_args,
-                                    stdout=subprocess.PIPE,
-                                    env=subprocess_environment)
-
-  if front_end_status.returncode != 0:
-    return front_end_status.returncode
-
-  back_end_status = subprocess.run(
-    [
-      sys.executable,
-      os.path.join(base_path, "compiler", "back_end", "cpp",
-        "emboss_codegen_cpp.py"),
-    ],
-    input=front_end_status.stdout,
-    stdout=subprocess.PIPE,
-    env=subprocess_environment
+  from compiler.back_end.cpp import ( # pylint:disable=import-outside-toplevel
+    emboss_codegen_cpp
+  )
+  from compiler.front_end import ( # pylint:disable=import-outside-toplevel
+    emboss_front_end
   )
 
-  if back_end_status.returncode != 0:
-    return back_end_status.returncode
+  ir, _, errors =  emboss_front_end.parse_and_log_errors(
+      flags.input_file[0], flags.import_dirs, flags.color_output)
+
+  if errors:
+    return 1
+
+  header, errors = emboss_codegen_cpp.generate_headers_and_log_errors(
+      ir, flags.color_output)
+
+  if errors:
+    return 1
 
   if flags.output_file:
     output_file = flags.output_file[0]
@@ -110,8 +88,8 @@
   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, "wb") as output:
-    output.write(back_end_status.stdout)
+  with open(output_filepath, "w") as output:
+    output.write(header)
   return 0