(* Authors: Sam Jayasinghe, Crystal Ren *)

(* Top-level of the Shoo compiler: scan & parse the input,
   check the resulting AST and generate an SAST from it, generate LLVM IR,
   and dump the module *)

type action = Ast | Sast | Lsast | LLVM_IR | Compile

let () =
  let action = ref Compile in
  let set_action a () = action := a in
  let speclist = [
    ("-a", Arg.Unit (set_action Ast), "Print the AST");
    ("-s", Arg.Unit (set_action Sast), "Print the SAST");
    ("-ls", Arg.Unit (set_action Lsast), "Print the LSAST");
    ("-l", Arg.Unit (set_action LLVM_IR), "Print the generated LLVM IR");
    ("-c", Arg.Unit (set_action Compile),
      "Check and print the generated LLVM IR (default)");
  ] in  
  let usage_msg = "usage: ./shoo.native [-a|-s|-l|-c] [file.shoo]" in
  let channel = ref stdin in
  Arg.parse speclist (fun filename -> channel := open_in filename) usage_msg;
  
  let lexbuf = Lexing.from_channel !channel in
  let ast = Parser.program Scanner.token lexbuf in  
  match !action with
    Ast -> print_string (Ast.string_of_program ast)
  | _ ->
    let sast = Semant.check_program ast in
    let lsast = Lift.lift sast in
    match !action with
      Ast     -> print_string (Ast.string_of_program ast)
    | Sast    -> print_string (Sast.string_of_sprogram sast)
    | Lsast   -> print_string (Lift.string_of_lsast lsast)
    | LLVM_IR -> print_string (Llvm.string_of_llmodule (Codegen.translate lsast))
    | Compile -> let m = Codegen.translate lsast in
      Llvm_analysis.assert_valid_module m;
      print_string (Llvm.string_of_llmodule m)
