Skip to content
Snippets Groups Projects
main.ml 4.83 KiB
open Params
open Format
open Mytools

(*
   Remark: field name attributes for builtins (eg: ::) are defined in attributes.ml
   Remark: field name attributes should not be "type" or "tag".
*)


(*#########################################################################*)

let ppf = Format.std_formatter
let stdlib_path = ref "stdlib_ml"

(* err_formatter *)


(*#########################################################################*)


let tool_name = "ml2js"

(** Configures the compilers load paths from the commandline and stdlib *)
(* FIXME: Relative stdlib dir should be absolute or findlib derived
 * we're manually specified using -I for now... *)
let init_path () =
  (* Compmisc.init_path false; (* to use this, lots of parameters need tweaking *)*)
  Config.load_path := "" :: List.rev_append !Clflags.include_dirs [!stdlib_path];
  Env.reset_cache ()

(** Return the initial environment in which compilation proceeds. *)
let initial_env () =
  Clflags.nopervasives := true;
  (* Stdlib module name, instead of Pervasives *)
  add_to_list Compenv.implicit_modules "Stdlib";
  Compmisc.initial_env ()


(** Analysis of an implementation file.
 *  ppf: error printer
 *  sourcefile: path/filename of source file
 *  oprefix: output file name prefix (possibly manually set with -o)
 **)
let process_implementation_file ppf sourcefile oprefix =
  init_path ();
  let modulename = Compenv.module_of_filename ppf sourcefile oprefix in
  Env.set_unit_name modulename;
  try
    let env = initial_env () in
    let parsetree = Pparse.parse_implementation ~tool_name ppf sourcefile in
    if !Clflags.dump_source then fprintf ppf "%a@." Pprintast.structure parsetree;
    let typing = Typemod.type_implementation sourcefile oprefix modulename env parsetree in
    (parsetree, typing, modulename)
  with e ->
    Location.report_exception ppf e;
    exit 2

let _ =
   (*---------------------------------------------------*)
   (* parsing of command line *)

   let files = ref [] in
   Arg.parse
     [ ("-stdlib", Arg.Set_string stdlib_path, "path to look for Stdlib (defaults to 'stdlib_ml')");
       ("-I", Arg.String (add_to_list Clflags.include_dirs), "includes a directory where to look for interface files");
       ("-o", Arg.String (fun s -> Clflags.output_name := Some s), "set the output file");
       ("-debug", Arg.Set debug, "trace the various steps");
       ("-dsource", Arg.Set Clflags.dump_source, "dump source after ppx");
       ("-ppx", Arg.String (add_to_list Clflags.all_ppx (* TODO Compenv.first_ppx *) ), "load ppx");
       ("-mode", Arg.String (fun s -> set_current_mode s), "current mode: unlog, log, or token")
     ]
     (fun f -> files := f :: !files)
     ("usage: [-I dir] [..other options..] file.ml");


   files := List.rev !files;
   if List.length !files <> 1 then
      failwith "Expects one argument: the filename of the ML source file";
   let sourcefile = List.hd !files in

   if not (Filename.check_suffix sourcefile ".ml") then
     failwith "The file name must be of the form *.ml";

   let sourcebase = Filename.basename sourcefile in   (* Input file basename, for logging *)
   let oprefix = Compenv.output_prefix sourcefile in (* Output filename prefix, inc. path *)
   let output_filename = oprefix ^ (get_mode_extension !current_mode) in
   let mlloc_output = oprefix ^ ".mlloc.js" in

   (*---------------------------------------------------*)
   (* set flags *)

   if !current_mode <> Mode_cmi
      then Clflags.dont_write_files := true;

   (* TODO: does not work because we don't have easy access to the fully qualified path of constructors
   if !current_mode <> Mode_unlogged 
      then generate_qualified_names := true;
   *)


   (*---------------------------------------------------*)
   (* generation of the mlloc file that binds tokens to positions *)

   let generate_mlloc_file () =
      let outchannel = open_out mlloc_output in
      let put = output_endline outchannel in
      put "   lineof_temp = [];";
      Js_of_ast.(
         ~~ Hashtbl.iter token_locs (fun key (pos_start,pos_stop) ->
           put (Printf.sprintf "   lineof_temp[%d] = [%d,%d,%d,%d];" 
                  key pos_start.pos_line pos_start.pos_col  
                      pos_stop.pos_line  pos_stop.pos_col);
         ));
      put (Printf.sprintf "lineof_data[\"%s\"] = lineof_temp;" sourcebase);
      close_out outchannel;
      Printf.printf "Wrote %s\n" mlloc_output;
      in

   (*---------------------------------------------------*)
   (* "reading and typing source file" *)

   let (parsetree, (typedtree,_), module_name) = process_implementation_file ppf sourcefile oprefix in
   if !current_mode <> Mode_cmi then begin
     let out = Js_of_ast.to_javascript sourcebase module_name typedtree in
     file_put_contents output_filename out;
     if !current_mode = (Mode_unlogged TokenTrue) 
       then generate_mlloc_file()
   end;
   Printf.printf "Wrote %s\n" output_filename