#! /usr/bin/env python
"""
Usage:
  cent (-h|--help)
  cent -i FILE
  cent -c [-k|--keep-c] FILE

Options:
  -h --help     Print this help screen
  -i            Run the interpreter
  -c            Run the compiler
  -k --keep-c   Keep the generated C file alongside the binary
  FILE          The file to compile/interpret
"""
import os
import subprocess
import sys
import tempfile

from docopt import docopt
from rply.errors import LexingError

from centvrion.errors import CentvrionError
from centvrion.lexer import Lexer
from centvrion.parser import Parser
from centvrion.ast_nodes import Program
from centvrion.compiler.emitter import compile_program

def main():
  args = docopt(__doc__)
  file_path = args["FILE"]
  with open(file_path, "r", encoding="utf-8") as file_pointer:
    program_text = file_pointer.read() + "\n"

  lexer = Lexer().get_lexer()
  parser = Parser()

  try:
    tokens = lexer.lex(program_text)
    program = parser.parse(tokens)
  except LexingError as e:
    pos = e.source_pos
    char = program_text[pos.idx] if pos.idx < len(program_text) else "?"
    sys.exit(f"CENTVRION error: Invalid character {char!r} at line {pos.lineno}, column {pos.colno}")
  except SyntaxError as e:
    sys.exit(f"CENTVRION error: {e}")

  if isinstance(program, Program):
    if args["-i"]:
      try:
        program.eval()
      except CentvrionError as e:
        sys.exit(f"CENTVRION error: {e}")
    else:
      c_source = compile_program(program)
      runtime_dir = os.path.join(
        os.path.dirname(__file__),
        "centvrion", "compiler", "runtime"
      )
      runtime_c = os.path.join(runtime_dir, "cent_runtime.c")
      iason_c = os.path.join(runtime_dir, "cent_iason.c")
      out_path = os.path.splitext(file_path)[0]
      if args["--keep-c"]:
        tmp_path = out_path + ".c"
        with open(tmp_path, "w") as f:
          f.write(c_source)
        subprocess.run(
          ["gcc", "-O2", tmp_path, runtime_c, iason_c, "-o", out_path, "-lcurl", "-lmicrohttpd", "-lm"],
          check=True,
        )
      else:
        with tempfile.NamedTemporaryFile(suffix=".c", delete=False, mode="w") as tmp:
          tmp.write(c_source)
          tmp_path = tmp.name
        try:
          subprocess.run(
            ["gcc", "-O2", tmp_path, runtime_c, iason_c, "-o", out_path, "-lcurl", "-lmicrohttpd", "-lm"],
            check=True,
          )
        finally:
          os.unlink(tmp_path)
  else:
    raise Exception("Output not of type 'Program'", type(program))

if __name__ == "__main__":
  main()
