jan_flanders

Untitled

Nov 30th, 2012
164
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (*
  2.  *  Haxe Compiler
  3.  *  Copyright (c)2005-2008 Nicolas Cannasse
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  *)
  19. open Printf
  20. open Genswf
  21. open Common
  22. open Type
  23.  
  24. type context = {
  25.     com : Common.context;
  26.     mutable flush : unit -> unit;
  27.     mutable setup : unit -> unit;
  28.     mutable messages : string list;
  29.     mutable has_next : bool;
  30.     mutable has_error : bool;
  31. }
  32.  
  33. type cache = {
  34.     mutable c_haxelib : (string list, string list) Hashtbl.t;
  35.     mutable c_files : (string, float * Ast.package) Hashtbl.t;
  36.     mutable c_modules : (path * string, module_def) Hashtbl.t;
  37. }
  38.  
  39. exception Abort
  40. exception Completion of string
  41.  
  42. let version = 211
  43.  
  44. let measure_times = ref false
  45. let prompt = ref false
  46. let start_time = ref (get_time())
  47. let global_cache = ref None
  48.  
  49. let executable_path() =
  50.     Extc.executable_path()
  51.  
  52. let format msg p =
  53.     if p = Ast.null_pos then
  54.         msg
  55.     else begin
  56.         let error_printer file line = sprintf "%s:%d:" file line in
  57.         let epos = Lexer.get_error_pos error_printer p in
  58.         let msg = String.concat ("\n" ^ epos ^ " : ") (ExtString.String.nsplit msg "\n") in
  59.         sprintf "%s : %s" epos msg
  60.     end
  61.  
  62. let ssend sock str =
  63.     let rec loop pos len =
  64.         if len = 0 then
  65.             ()
  66.         else
  67.             let s = Unix.send sock str pos len [] in
  68.             loop (pos + s) (len - s)
  69.     in
  70.     loop 0 (String.length str)
  71.  
  72. let message ctx msg p =
  73.     ctx.messages <- format msg p :: ctx.messages
  74.  
  75. let error ctx msg p =
  76.     message ctx msg p;
  77.     ctx.has_error <- true
  78.  
  79. let htmlescape s =
  80.     let s = String.concat "&amp;" (ExtString.String.nsplit s "&") in
  81.     let s = String.concat "&lt;" (ExtString.String.nsplit s "<") in
  82.     let s = String.concat "&gt;" (ExtString.String.nsplit s ">") in
  83.     s
  84.  
  85. let reserved_flags = [
  86.     "cross";"flash8";"js";"neko";"flash";"php";"cpp";"cs";"java";
  87.     "as3";"swc";"macro";"sys"
  88.     ]
  89.  
  90. let complete_fields fields =
  91.     let b = Buffer.create 0 in
  92.     Buffer.add_string b "<list>\n";
  93.     List.iter (fun (n,t,d) ->
  94.         Buffer.add_string b (Printf.sprintf "<i n=\"%s\"><t>%s</t><d>%s</d></i>\n" n (htmlescape t) (htmlescape d))
  95.     ) (List.sort (fun (a,_,_) (b,_,_) -> compare a b) fields);
  96.     Buffer.add_string b "</list>\n";
  97.     raise (Completion (Buffer.contents b))
  98.  
  99. let report_times print =
  100.     let tot = ref 0. in
  101.     Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
  102.     print (Printf.sprintf "Total time : %.3fs" !tot);
  103.     if !tot > 0. then begin
  104.         print "------------------------------------";
  105.         let timers = List.sort (fun t1 t2 -> compare t1.name t2.name) (Hashtbl.fold (fun _ t acc -> t :: acc) Common.htimers []) in
  106.         List.iter (fun t -> print (Printf.sprintf "  %s : %.3fs, %.0f%%" t.name t.total (t.total *. 100. /. !tot))) timers
  107.     end
  108.  
  109. let make_path f =
  110.     let f = String.concat "/" (ExtString.String.nsplit f "\\") in
  111.     let cl = ExtString.String.nsplit f "." in
  112.     let cl = (match List.rev cl with
  113.         | ["hx";path] -> ExtString.String.nsplit path "/"
  114.         | _ -> cl
  115.     ) in
  116.     let error() = failwith ("Invalid class name " ^ f) in
  117.     let invalid_char x =
  118.         for i = 1 to String.length x - 1 do
  119.             match x.[i] with
  120.             | 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' -> ()
  121.             | _ -> error()
  122.         done;
  123.         false
  124.     in
  125.     let rec loop = function
  126.         | [] -> error()
  127.         | [x] -> if String.length x = 0 || not (x.[0] = '_' || (x.[0] >= 'A' && x.[0] <= 'Z')) || invalid_char x then error() else [] , x
  128.         | x :: l ->
  129.             if String.length x = 0 || x.[0] < 'a' || x.[0] > 'z' || invalid_char x then error() else
  130.                 let path , name = loop l in
  131.                 x :: path , name
  132.     in
  133.     loop cl
  134.  
  135. let unique l =
  136.     let rec _unique = function
  137.         | [] -> []
  138.         | x1 :: x2 :: l when x1 = x2 -> _unique (x2 :: l)
  139.         | x :: l -> x :: _unique l
  140.     in
  141.     _unique (List.sort compare l)
  142.  
  143. let rec read_type_path com p =
  144.     let classes = ref [] in
  145.     let packages = ref [] in
  146.     let p = (match p with
  147.         | x :: l ->
  148.             (try
  149.                 match PMap.find x com.package_rules with
  150.                 | Directory d -> d :: l
  151.                 | Remap s -> s :: l
  152.                 | _ -> p
  153.             with
  154.                 Not_found -> p)
  155.         | _ -> p
  156.     ) in
  157.     List.iter (fun path ->
  158.         let dir = path ^ String.concat "/" p in
  159.         let r = (try Sys.readdir dir with _ -> [||]) in
  160.         Array.iter (fun f ->
  161.             if (try (Unix.stat (dir ^ "/" ^ f)).Unix.st_kind = Unix.S_DIR with _ -> false) then begin
  162.                 if f.[0] >= 'a' && f.[0] <= 'z' then begin
  163.                     if p = ["."] then
  164.                         match read_type_path com [f] with
  165.                         | [] , [] -> ()
  166.                         | _ ->
  167.                             try
  168.                                 match PMap.find f com.package_rules with
  169.                                 | Forbidden -> ()
  170.                                 | Remap f -> packages := f :: !packages
  171.                                 | Directory _ -> raise Not_found
  172.                             with Not_found ->
  173.                                 packages := f :: !packages
  174.                     else
  175.                         packages := f :: !packages
  176.                 end;
  177.             end else if file_extension f = "hx" then begin
  178.                 let c = Filename.chop_extension f in
  179.                 if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
  180.             end;
  181.         ) r;
  182.     ) com.class_path;
  183.     List.iter (fun (_,_,extract) ->
  184.         Hashtbl.iter (fun (path,name) _ ->
  185.             if path = p then classes := name :: !classes else
  186.             let rec loop p1 p2 =
  187.                 match p1, p2 with
  188.                 | [], _ -> ()
  189.                 | x :: _, [] -> packages := x :: !packages
  190.                 | a :: p1, b :: p2 -> if a = b then loop p1 p2
  191.             in
  192.             loop path p
  193.         ) (extract());
  194.     ) com.swf_libs;
  195.     unique !packages, unique !classes
  196.  
  197. let delete_file f = try Sys.remove f with _ -> ()
  198.  
  199. let expand_env ?(h=None) path  =
  200.     let r = Str.regexp "%\\([A-Za-z0-9_]+\\)%" in
  201.     Str.global_substitute r (fun s ->
  202.         let key = Str.matched_group 1 s in
  203.         try
  204.             Sys.getenv key
  205.         with Not_found -> try
  206.             match h with
  207.             | None -> raise Not_found
  208.             | Some h -> Hashtbl.find h key
  209.         with Not_found ->
  210.             "%" ^ key ^ "%"
  211.     ) path
  212.  
  213. let unquote v =
  214.     let len = String.length v in
  215.     if len > 0 && v.[0] = '"' && v.[len - 1] = '"' then String.sub v 1 (len - 2) else v
  216.  
  217. let parse_hxml_data data =
  218.     let lines = Str.split (Str.regexp "[\r\n]+") data in
  219.     List.concat (List.map (fun l ->
  220.         let l = unquote (ExtString.String.strip l) in
  221.         if l = "" || l.[0] = '#' then
  222.             []
  223.         else if l.[0] = '-' then
  224.             try
  225.                 let a, b = ExtString.String.split l " " in
  226.                 [unquote a; unquote (ExtString.String.strip b)]
  227.             with
  228.                 _ -> [l]
  229.         else
  230.             [l]
  231.     ) lines)
  232.  
  233. let parse_hxml file =
  234.     let ch = IO.input_channel (try open_in_bin file with _ -> failwith ("File not found " ^ file)) in
  235.     let data = IO.read_all ch in
  236.     IO.close_in ch;
  237.     parse_hxml_data data
  238.  
  239. let lookup_classes com spath =
  240.     let rec loop = function
  241.         | [] -> []
  242.         | cp :: l ->
  243.             let cp = (if cp = "" then "./" else cp) in
  244.             let c = normalize_path (Extc.get_real_path (Common.unique_full_path cp)) in
  245.             let clen = String.length c in
  246.             if clen < String.length spath && String.sub spath 0 clen = c then begin
  247.                 let path = String.sub spath clen (String.length spath - clen) in
  248.                 (try
  249.                     let path = make_path path in
  250.                     (match loop l with
  251.                     | [x] when String.length (Ast.s_type_path x) < String.length (Ast.s_type_path path) -> [x]
  252.                     | _ -> [path])
  253.                 with _ -> loop l)
  254.             end else
  255.                 loop l
  256.     in
  257.     loop com.class_path
  258.  
  259. let add_libs com libs =
  260.     let call_haxelib() =
  261.         let t = Common.timer "haxelib" in
  262.         let cmd = "haxelib path " ^ String.concat " " libs in
  263.         let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
  264.         let lines = Std.input_list pin in
  265.         let err = Std.input_list perr in
  266.         let ret = Unix.close_process_full (pin,pout,perr) in
  267.         if ret <> Unix.WEXITED 0 then failwith (match lines, err with
  268.             | [], [] -> "Failed to call haxelib (command not found ?)"
  269.             | [], [s] when ExtString.String.ends_with (ExtString.String.strip s) "Module not found : path" -> "The haxelib command has been strip'ed, please install it again"
  270.             | _ -> String.concat "\n" (lines@err));
  271.         t();
  272.         lines
  273.     in
  274.     match libs with
  275.     | [] -> []
  276.     | _ ->
  277.         let lines = match !global_cache with
  278.             | Some cache ->
  279.                 (try
  280.                     (* if we are compiling, really call haxelib since library path might have changed *)
  281.                     if not com.display then raise Not_found;
  282.                     Hashtbl.find cache.c_haxelib libs
  283.                 with Not_found ->
  284.                     let lines = call_haxelib() in
  285.                     Hashtbl.replace cache.c_haxelib libs lines;
  286.                     lines)
  287.             | _ -> call_haxelib()
  288.         in
  289.         let extra_args = ref [] in
  290.         let lines = List.fold_left (fun acc l ->
  291.             let l = ExtString.String.strip l in
  292.             if l = "" then acc else
  293.             if l.[0] <> '-' then l :: acc else
  294.             match (try ExtString.String.split l " " with _ -> l, "") with
  295.             | ("-L",dir) ->
  296.                 com.neko_libs <- String.sub l 3 (String.length l - 3) :: com.neko_libs;
  297.                 acc
  298.             | param, value ->
  299.                 extra_args := param :: !extra_args;
  300.                 if value <> "" then extra_args := value :: !extra_args;
  301.                 acc
  302.         ) [] lines in
  303.         com.class_path <- lines @ com.class_path;
  304.         List.rev !extra_args
  305.  
  306. let run_command ctx cmd =
  307.     let h = Hashtbl.create 0 in
  308.     Hashtbl.add h "__file__" ctx.com.file;
  309.     Hashtbl.add h "__platform__" (platform_name ctx.com.platform);
  310.     let t = Common.timer "command" in
  311.     let cmd = expand_env ~h:(Some h) cmd in
  312.     let len = String.length cmd in
  313.     if len > 3 && String.sub cmd 0 3 = "cd " then
  314.         Sys.chdir (String.sub cmd 3 (len - 3))
  315.     else
  316.     let binary_string s =
  317.         if Sys.os_type <> "Win32" && Sys.os_type <> "Cygwin" then s else String.concat "\n" (Str.split (Str.regexp "\r\n") s)
  318.     in
  319.     let pout, pin, perr = Unix.open_process_full cmd (Unix.environment()) in
  320.     let iout = Unix.descr_of_in_channel pout in
  321.     let ierr = Unix.descr_of_in_channel perr in
  322.     let berr = Buffer.create 0 in
  323.     let bout = Buffer.create 0 in
  324.     let tmp = String.create 1024 in
  325.     let result = ref None in
  326.     (*
  327.         we need to read available content on process out/err if we want to prevent
  328.         the process from blocking when the pipe is full
  329.     *)
  330.     let is_process_running() =
  331.         let pid, r = Unix.waitpid [Unix.WNOHANG] (-1) in
  332.         if pid = 0 then
  333.             true
  334.         else begin
  335.             result := Some r;
  336.             false;
  337.         end
  338.     in
  339.     let rec loop ins =
  340.         let (ch,_,_), timeout = (try Unix.select ins [] [] 0.02, true with _ -> ([],[],[]),false) in
  341.         match ch with
  342.         | [] ->
  343.             (* make sure we read all *)
  344.             if timeout && is_process_running() then
  345.                 loop ins
  346.             else begin
  347.                 Buffer.add_string berr (IO.read_all (IO.input_channel perr));
  348.                 Buffer.add_string bout (IO.read_all (IO.input_channel pout));
  349.             end
  350.         | s :: _ ->
  351.             let n = Unix.read s tmp 0 (String.length tmp) in
  352.             Buffer.add_substring (if s == iout then bout else berr) tmp 0 n;
  353.             loop (if n = 0 then List.filter ((!=) s) ins else ins)
  354.     in
  355.     (try loop [iout;ierr] with Unix.Unix_error _ -> ());
  356.     let serr = binary_string (Buffer.contents berr) in
  357.     let sout = binary_string (Buffer.contents bout) in
  358.     if serr <> "" then ctx.messages <- (if serr.[String.length serr - 1] = '\n' then String.sub serr 0 (String.length serr - 1) else serr) :: ctx.messages;
  359.     if sout <> "" then ctx.com.print sout;
  360.     (match (try Unix.close_process_full (pout,pin,perr) with Unix.Unix_error (Unix.ECHILD,_,_) -> (match !result with None -> assert false | Some r -> r)) with
  361.     | Unix.WEXITED e -> if e <> 0 then failwith ("Command failed with error " ^ string_of_int e)
  362.     | Unix.WSIGNALED s | Unix.WSTOPPED s -> failwith ("Command stopped with signal " ^ string_of_int s));
  363.     t()
  364.  
  365. let default_flush ctx =
  366.     List.iter prerr_endline (List.rev ctx.messages);
  367.     if ctx.has_error && !prompt then begin
  368.         print_endline "Press enter to exit...";
  369.         ignore(read_line());
  370.     end;
  371.     if ctx.has_error then exit 1
  372.  
  373. let create_context params =
  374.     let ctx = {
  375.         com = Common.create version params;
  376.         flush = (fun()->());
  377.         setup = (fun()->());
  378.         messages = [];
  379.         has_next = false;
  380.         has_error = false;
  381.     } in
  382.     ctx.flush <- (fun() -> default_flush ctx);
  383.     ctx
  384.  
  385. let rec process_params create pl =
  386.     let each_params = ref [] in
  387.     let rec loop acc = function
  388.         | [] ->
  389.             let ctx = create (!each_params @ (List.rev acc)) in
  390.             init ctx;
  391.             ctx.flush()
  392.         | "--next" :: l when acc = [] -> (* skip empty --next *)
  393.             loop [] l
  394.         | "--next" :: l ->
  395.             let ctx = create (!each_params @ (List.rev acc)) in
  396.             ctx.has_next <- true;
  397.             init ctx;
  398.             ctx.flush();
  399.             loop [] l
  400.         | "--each" :: l ->
  401.             each_params := List.rev acc;
  402.             loop [] l
  403.         | "--cwd" :: dir :: l ->
  404.             (* we need to change it immediately since it will affect hxml loading *)
  405.             (try Unix.chdir dir with _ -> ());
  406.             loop (dir :: "--cwd" :: acc) l
  407.         | "--connect" :: hp :: l ->
  408.             (match !global_cache with
  409.             | None ->
  410.                 let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
  411.                 do_connect host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port")) ((List.rev acc) @ l)
  412.             | Some _ ->
  413.                 (* already connected : skip *)
  414.                 loop acc l)
  415.         | arg :: l ->
  416.             match List.rev (ExtString.String.nsplit arg ".") with
  417.             | "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) -> loop acc (parse_hxml arg @ l)
  418.             | _ -> loop (arg :: acc) l
  419.     in
  420.     (* put --display in front if it was last parameter *)
  421.     let pl = (match List.rev pl with
  422.         | file :: "--display" :: pl -> "--display" :: file :: List.rev pl
  423.         | "use_rtti_doc" :: "-D" :: file :: "--display" :: pl -> "--display" :: file :: List.rev pl
  424.         | _ -> pl
  425.     ) in
  426.     loop [] pl
  427.  
  428. and wait_loop boot_com host port =
  429.     let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
  430.     (try Unix.bind sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't wait on " ^ host ^ ":" ^ string_of_int port));
  431.     Unix.listen sock 10;
  432.     Sys.catch_break false;
  433.     let verbose = boot_com.verbose in
  434.     let has_parse_error = ref false in
  435.     if verbose then print_endline ("Waiting on " ^ host ^ ":" ^ string_of_int port);
  436.     let bufsize = 1024 in
  437.     let tmp = String.create bufsize in
  438.     let cache = {
  439.         c_haxelib = Hashtbl.create 0;
  440.         c_files = Hashtbl.create 0;
  441.         c_modules = Hashtbl.create 0;
  442.     } in
  443.     global_cache := Some cache;
  444.     Typeload.parse_hook := (fun com2 file p ->
  445.         let sign = get_signature com2 in
  446.         let ffile = Common.unique_full_path file in
  447.         let ftime = file_time ffile in
  448.         let fkey = ffile ^ "!" ^ sign in
  449.         try
  450.             let time, data = Hashtbl.find cache.c_files fkey in
  451.             if time <> ftime then raise Not_found;
  452.             data
  453.         with Not_found ->
  454.             has_parse_error := false;
  455.             let data = Typeload.parse_file com2 file p in
  456.             if verbose then print_endline ("Parsed " ^ ffile);
  457.             if not !has_parse_error && ffile <> (!Parser.resume_display).Ast.pfile then Hashtbl.replace cache.c_files fkey (ftime,data);
  458.             data
  459.     );
  460.     let cache_module m =
  461.         Hashtbl.replace cache.c_modules (m.m_path,m.m_extra.m_sign) m;
  462.     in
  463.     let check_module_path com m p =
  464.         m.m_extra.m_file = Common.unique_full_path (Typeload.resolve_module_file com m.m_path (ref[]) p)
  465.     in
  466.     let compilation_step = ref 0 in
  467.     let compilation_mark = ref 0 in
  468.     let mark_loop = ref 0 in
  469.     Typeload.type_module_hook := (fun (ctx:Typecore.typer) mpath p ->
  470.         let t = Common.timer "module cache check" in
  471.         let com2 = ctx.Typecore.com in
  472.         let sign = get_signature com2 in
  473.         let dep = ref None in
  474.         incr mark_loop;
  475.         let mark = !mark_loop in
  476.         let start_mark = !compilation_mark in
  477.         let rec check m =
  478.             if m.m_extra.m_dirty then begin
  479.                 dep := Some m;
  480.                 false
  481.             end else if m.m_extra.m_mark = mark then
  482.                 true
  483.             else try
  484.                 if m.m_extra.m_mark <= start_mark then begin
  485.                     (match m.m_extra.m_kind with
  486.                     | MFake -> () (* don't get classpath *)
  487.                     | MCode -> if not (check_module_path com2 m p) then raise Not_found;
  488.                     | MMacro when ctx.Typecore.in_macro -> if not (check_module_path com2 m p) then raise Not_found;
  489.                     | MMacro ->
  490.                         let _, mctx = Typer.get_macro_context ctx p in
  491.                         if not (check_module_path mctx.Typecore.com m p) then raise Not_found;
  492.                     );
  493.                     if file_time m.m_extra.m_file <> m.m_extra.m_time then begin
  494.                         if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules m.m_extra.m_file;
  495.                         raise Not_found;
  496.                     end;
  497.                 end;
  498.                 m.m_extra.m_mark <- mark;
  499.                 PMap.iter (fun _ m2 -> if not (check m2) then begin dep := Some m2; raise Not_found end) m.m_extra.m_deps;
  500.                 true
  501.             with Not_found ->
  502.                 m.m_extra.m_dirty <- true;
  503.                 false
  504.         in
  505.         let rec add_modules m0 m =
  506.             if m.m_extra.m_added < !compilation_step then begin
  507.                 (match m0.m_extra.m_kind, m.m_extra.m_kind with
  508.                 | MCode, MMacro | MMacro, MCode ->
  509.                     (* this was just a dependency to check : do not add to the context *)
  510.                     ()
  511.                 | _ ->
  512.                     if verbose then print_endline ("Reusing  cached module " ^ Ast.s_type_path m.m_path);
  513.                     m.m_extra.m_added <- !compilation_step;
  514.                     List.iter (fun t ->
  515.                         match t with
  516.                         | TClassDecl c -> c.cl_restore()
  517.                         | TEnumDecl e ->
  518.                             let rec loop acc = function
  519.                                 | [] -> ()
  520.                                 | (":realPath",[Ast.EConst (Ast.String path),_],_) :: l ->
  521.                                     e.e_path <- Ast.parse_path path;
  522.                                     e.e_meta <- (List.rev acc) @ l;
  523.                                 | x :: l -> loop (x::acc) l
  524.                             in
  525.                             loop [] e.e_meta
  526.                         | _ -> ()
  527.                     ) m.m_types;
  528.                     Typeload.add_module ctx m p;
  529.                     PMap.iter (Hashtbl.add com2.resources) m.m_extra.m_binded_res;
  530.                     PMap.iter (fun _ m2 -> add_modules m0 m2) m.m_extra.m_deps);
  531.                     List.iter (Typer.call_init_macro ctx) m.m_extra.m_macro_calls
  532.             end
  533.         in
  534.         try
  535.             let m = Hashtbl.find cache.c_modules (mpath,sign) in
  536.             if not (check m) then begin
  537.                 if verbose then print_endline ("Skipping cached module " ^ Ast.s_type_path mpath ^ (match !dep with None -> "" | Some m -> "(" ^ Ast.s_type_path m.m_path ^ ")"));
  538.                 raise Not_found;
  539.             end;
  540.             add_modules m m;
  541.             t();
  542.             Some m
  543.         with Not_found ->
  544.             t();
  545.             None
  546.     );
  547.     let run_count = ref 0 in
  548.     while true do
  549.         let sin, _ = Unix.accept sock in
  550.         let t0 = get_time() in
  551.         Unix.set_nonblock sin;
  552.         if verbose then print_endline "Client connected";
  553.         let b = Buffer.create 0 in
  554.         let rec read_loop() =
  555.             try
  556.                 let r = Unix.recv sin tmp 0 bufsize [] in
  557.                 if verbose then Printf.printf "Reading %d bytes\n" r;
  558.                 Buffer.add_substring b tmp 0 r;
  559.                 if r > 0 && tmp.[r-1] = '\000' then Buffer.sub b 0 (Buffer.length b - 1) else read_loop();
  560.             with Unix.Unix_error((Unix.EWOULDBLOCK|Unix.EAGAIN),_,_) ->
  561.                 if verbose then print_endline "Waiting for data...";
  562.                 ignore(Unix.select [] [] [] 0.1);
  563.                 read_loop()
  564.         in
  565.         let rec cache_context com =
  566.             if not com.display then begin
  567.                 List.iter cache_module com.modules;
  568.                 if verbose then print_endline ("Cached " ^ string_of_int (List.length com.modules) ^ " modules");
  569.             end;
  570.             match com.get_macros() with
  571.             | None -> ()
  572.             | Some com -> cache_context com
  573.         in
  574.         let create params =
  575.             let ctx = create_context params in
  576.             ctx.flush <- (fun() ->
  577.                 incr compilation_step;
  578.                 compilation_mark := !mark_loop;
  579.                 List.iter (fun s -> ssend sin (s ^ "\n"); if verbose then print_endline ("> " ^ s)) (List.rev ctx.messages);
  580.                 if ctx.has_error then ssend sin "\x02\n" else cache_context ctx.com;
  581.             );
  582.             ctx.setup <- (fun() ->
  583.                 Parser.display_error := (fun e p -> has_parse_error := true; ctx.com.error (Parser.error_msg e) p);
  584.                 if ctx.com.display then begin
  585.                     let file = (!Parser.resume_display).Ast.pfile in
  586.                     let fkey = file ^ "!" ^ get_signature ctx.com in
  587.                     (* force parsing again : if the completion point have been changed *)
  588.                     Hashtbl.remove cache.c_files fkey;
  589.                     (* force module reloading (if cached) *)
  590.                     Hashtbl.iter (fun _ m -> if m.m_extra.m_file = file then m.m_extra.m_dirty <- true) cache.c_modules
  591.                 end
  592.             );
  593.             ctx.com.print <- (fun str -> ssend sin ("\x01" ^ String.concat "\x01" (ExtString.String.nsplit str "\n") ^ "\n"));
  594.             ctx
  595.         in
  596.         (try
  597.             let data = parse_hxml_data (read_loop()) in
  598.             Unix.clear_nonblock sin;
  599.             if verbose then print_endline ("Processing Arguments [" ^ String.concat "," data ^ "]");
  600.             (try
  601.                 Common.display_default := false;
  602.                 Parser.resume_display := Ast.null_pos;
  603.                 Typeload.return_partial_type := false;
  604.                 measure_times := false;
  605.                 close_times();
  606.                 stats.s_files_parsed := 0;
  607.                 stats.s_classes_built := 0;
  608.                 stats.s_methods_typed := 0;
  609.                 stats.s_macros_called := 0;
  610.                 Hashtbl.clear Common.htimers;
  611.                 let _ = Common.timer "other" in
  612.                 incr compilation_step;
  613.                 compilation_mark := !mark_loop;
  614.                 start_time := get_time();
  615.                 process_params create data;
  616.                 close_times();
  617.                 if !measure_times then report_times (fun s -> ssend sin (s ^ "\n"))
  618.             with Completion str ->
  619.                 if verbose then print_endline ("Completion Response =\n" ^ str);
  620.                 ssend sin str
  621.             );
  622.             if verbose then begin
  623.                 print_endline (Printf.sprintf "Stats = %d files, %d classes, %d methods, %d macros" !(stats.s_files_parsed) !(stats.s_classes_built) !(stats.s_methods_typed) !(stats.s_macros_called));
  624.                 print_endline (Printf.sprintf "Time spent : %.3fs" (get_time() -. t0));
  625.             end
  626.         with Unix.Unix_error _ ->
  627.             if verbose then print_endline "Connection Aborted");
  628.         Unix.close sin;
  629.         (* prevent too much fragmentation by doing some compactions every X run *)
  630.         incr run_count;
  631.         if !run_count mod 1 = 50 then begin
  632.             let t0 = get_time() in
  633.             Gc.compact();
  634.             if verbose then begin
  635.                 let stat = Gc.quick_stat() in
  636.                 let size = (float_of_int stat.Gc.heap_words) *. 4. in
  637.                 print_endline (Printf.sprintf "Compacted memory %.3fs %.1fMB" (get_time() -. t0) (size /. (1024. *. 1024.)));
  638.             end
  639.         end else Gc.minor();
  640.     done
  641.  
  642. and do_connect host port args =
  643.     let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
  644.     (try Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_of_string host,port)) with _ -> failwith ("Couldn't connect on " ^ host ^ ":" ^ string_of_int port));
  645.     let args = ("--cwd " ^ Unix.getcwd()) :: args in
  646.     ssend sock (String.concat "" (List.map (fun a -> a ^ "\n") args) ^ "\000");
  647.     let buf = Buffer.create 0 in
  648.     let tmp = String.create 100 in
  649.     let rec loop() =
  650.         let b = Unix.recv sock tmp 0 100 [] in
  651.         Buffer.add_substring buf tmp 0 b;
  652.         if b > 0 then loop()
  653.     in
  654.     loop();
  655.     let has_error = ref false in
  656.     let rec print line =
  657.         match (if line = "" then '\x00' else line.[0]) with
  658.         | '\x01' ->
  659.             print_string (String.concat "\n" (List.tl (ExtString.String.nsplit line "\x01")))
  660.         | '\x02' ->
  661.             has_error := true;
  662.         | _ ->
  663.             prerr_endline line;
  664.     in
  665.     let lines = ExtString.String.nsplit (Buffer.contents buf) "\n" in
  666.     let lines = (match List.rev lines with "" :: l -> List.rev l | _ -> lines) in
  667.     List.iter print lines;
  668.     if !has_error then exit 1
  669.  
  670. and init ctx =
  671.     let usage = Printf.sprintf
  672.         "Haxe Compiler %d.%.2d - (c)2005-2012 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-cs|-java|-as3] <output> [options]\n Options :"
  673.         (version / 100) (version mod 100) (if Sys.os_type = "Win32" then ".exe" else "")
  674.     in
  675.     let com = ctx.com in
  676.     let classes = ref [([],"Std")] in
  677. try
  678.     let xml_out = ref None in
  679.     let swf_header = ref None in
  680.     let swf_script_limits = ref None in
  681.     let cmds = ref [] in
  682.     let config_macros = ref [] in
  683.     let cp_libs = ref [] in
  684.     let gen_as3 = ref false in
  685.     let no_output = ref false in
  686.     let did_something = ref false in
  687.     let force_typing = ref false in
  688.     let pre_compilation = ref [] in
  689.     let interp = ref false in
  690.     if version < 300 then begin
  691.         for i = 0 to 4 do
  692.             let v = version - i in
  693.             Common.raw_define com ("haxe_" ^ string_of_int v);
  694.         done;
  695.     end else begin
  696.         Common.define com Define.Haxe3;
  697.         Common.define_value com Define.HaxeVer (string_of_float (float_of_int version /. 100.));
  698.     end;
  699.     Common.define_value com Define.Dce "std";
  700.     com.warning <- (fun msg p -> message ctx ("Warning : " ^ msg) p);
  701.     com.error <- error ctx;
  702.     Parser.display_error := (fun e p -> com.error (Parser.error_msg e) p);
  703.     Parser.use_doc := !Common.display_default || (!global_cache <> None);
  704.     (try
  705.         let p = Sys.getenv "HAXE_LIBRARY_PATH" in
  706.         let rec loop = function
  707.             | drive :: path :: l ->
  708.                 if String.length drive = 1 && ((drive.[0] >= 'a' && drive.[0] <= 'z') || (drive.[0] >= 'A' && drive.[0] <= 'Z')) then
  709.                     (drive ^ ":" ^ path) :: loop l
  710.                 else
  711.                     drive :: loop (path :: l)
  712.             | l ->
  713.                 l
  714.         in
  715.         let parts = "" :: Str.split_delim (Str.regexp "[;:]") p in
  716.         com.class_path <- List.map normalize_path (loop parts)
  717.     with
  718.         Not_found ->
  719.             if Sys.os_type = "Unix" then
  720.                 com.class_path <- ["/usr/lib/haxe/std/";"/usr/local/lib/haxe/std/";"/usr/lib/haxe/std/libs/";"/usr/local/lib/haxe/std/libs/";"";"/"]
  721.             else
  722.                 let base_path = normalize_path (Extc.get_real_path (try executable_path() with _ -> "./")) in
  723.                 com.class_path <- [base_path ^ "std/";base_path ^ "std/libs/";""]);
  724.     com.std_path <- List.filter (fun p -> ExtString.String.ends_with p "std/" || ExtString.String.ends_with p "std\\") com.class_path;
  725.     let set_platform pf file =
  726.         if com.platform <> Cross then failwith "Multiple targets";
  727.         Common.init_platform com pf;
  728.         com.file <- file;
  729.         if (pf = Flash8 || pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc;
  730.     in
  731.     let define f = Arg.Unit (fun () -> Common.define com f) in
  732.     let extra_args = ref [] in
  733.     let basic_args_spec = [
  734.         ("-cp",Arg.String (fun path ->
  735.             extra_args := !extra_args @ (add_libs com (!cp_libs));
  736.             cp_libs := [];
  737.             com.class_path <- normalize_path path :: com.class_path
  738.         ),"<path> : add a directory to find source files");
  739.         ("-js",Arg.String (set_platform Js),"<file> : compile code to JavaScript file");
  740.         ("-swf",Arg.String (set_platform Flash),"<file> : compile code to Flash SWF file");
  741.         ("-as3",Arg.String (fun dir ->
  742.             set_platform Flash dir;
  743.             gen_as3 := true;
  744.             Common.define com Define.As3;
  745.             Common.define com Define.NoInline;
  746.         ),"<directory> : generate AS3 code into target directory");
  747.         ("-neko",Arg.String (set_platform Neko),"<file> : compile code to Neko Binary");
  748.         ("-php",Arg.String (fun dir ->
  749.             classes := (["php"],"Boot") :: !classes;
  750.             set_platform Php dir;
  751.         ),"<directory> : generate PHP code into target directory");
  752.         ("-cpp",Arg.String (fun dir ->
  753.             set_platform Cpp dir;
  754.         ),"<directory> : generate C++ code into target directory");
  755.         ("-cs",Arg.String (fun dir ->
  756.             set_platform Cs dir;
  757.         ),"<directory> : generate C# code into target directory");
  758.         ("-java",Arg.String (fun dir ->
  759.             set_platform Java dir;
  760.         ),"<directory> : generate Java code into target directory");
  761.         ("-xml",Arg.String (fun file ->
  762.             Parser.use_doc := true;
  763.             xml_out := Some file
  764.         ),"<file> : generate XML types description");
  765.         ("-main",Arg.String (fun cl ->
  766.             if com.main_class <> None then raise (Arg.Bad "Multiple -main");
  767.             let cpath = make_path cl in
  768.             com.main_class <- Some cpath;
  769.             classes := cpath :: !classes
  770.         ),"<class> : select startup class");
  771.         ("-lib",Arg.String (fun l ->
  772.             cp_libs := l :: !cp_libs;
  773.             Common.raw_define com l;
  774.         ),"<library[:version]> : use a haxelib library");
  775.         ("-D",Arg.String (fun var ->
  776.             if var = fst (Define.infos Define.UseRttiDoc) then Parser.use_doc := true;
  777.             if var = fst (Define.infos Define.NoOpt) then com.foptimize <- false;
  778.             if List.mem var reserved_flags then raise (Arg.Bad (var ^ " is a reserved compiler flag and cannot be defined from command line"));
  779.             Common.raw_define com var
  780.         ),"<var> : define a conditional compilation flag");
  781.         ("-v",Arg.Unit (fun () ->
  782.             com.verbose <- true
  783.         ),": turn on verbose mode");
  784.         ("-debug", Arg.Unit (fun() ->
  785.             Common.define com Define.Debug;
  786.             com.debug <- true;
  787.         ), ": add debug informations to the compiled code");
  788.     ] in
  789.     let adv_args_spec = [
  790.         ("-swf-version",Arg.Float (fun v ->
  791.             com.flash_version <- v;
  792.         ),"<version> : change the SWF version (6 to 10)");
  793.         ("-swf-header",Arg.String (fun h ->
  794.             try
  795.                 swf_header := Some (match ExtString.String.nsplit h ":" with
  796.                 | [width; height; fps] ->
  797.                     (int_of_string width,int_of_string height,float_of_string fps,0xFFFFFF)
  798.                 | [width; height; fps; color] ->
  799.                     (int_of_string width, int_of_string height, float_of_string fps, int_of_string ("0x" ^ color))
  800.                 | _ -> raise Exit)
  801.             with
  802.                 _ -> raise (Arg.Bad "Invalid SWF header format")
  803.         ),"<header> : define SWF header (width:height:fps:color)");
  804.         ("-swf-script-limits",Arg.String (fun sl ->
  805.             try
  806.                 com.swf_script_limits := Some (match ExtString.String.nsplit sl ":" with
  807.                 | [recursion_depth; script_timeout] -> (int_of_string recursion_depth, int_of_string script_timeout)
  808.                 | _ -> raise Exit)
  809.             with
  810.                 _ -> raise (Arg.Bad "Invalid SWF ScriptLimits format")
  811.         ),"<swf script limits> : define SWF script limits (recursion depth:script timeout)");
  812.         ("-swf-lib",Arg.String (fun file ->
  813.             Genswf.add_swf_lib com file
  814.         ),"<file> : add the SWF library to the compiled SWF");
  815.         ("-java-lib",Arg.String (fun file ->
  816.             Genjava.add_java_lib com file
  817.         ),"<file> : add an external JAR or class directory library");
  818.         ("-x", Arg.String (fun file ->
  819.             let neko_file = file ^ ".n" in
  820.             set_platform Neko neko_file;
  821.             if com.main_class = None then begin
  822.                 let cpath = make_path file in
  823.                 com.main_class <- Some cpath;
  824.                 classes := cpath :: !classes
  825.             end;
  826.             cmds := ("neko " ^ neko_file) :: !cmds;
  827.         ),"<file> : shortcut for compiling and executing a neko file");
  828.         ("-resource",Arg.String (fun res ->
  829.             let file, name = (match ExtString.String.nsplit res "@" with
  830.                 | [file; name] -> file, name
  831.                 | [file] -> file, file
  832.                 | _ -> raise (Arg.Bad "Invalid Resource format : should be file@name")
  833.             ) in
  834.             let file = (try Common.find_file com file with Not_found -> file) in
  835.             let data = (try
  836.                 let s = Std.input_file ~bin:true file in
  837.                 if String.length s > 12000000 then raise Exit;
  838.                 s;
  839.             with
  840.                 | Sys_error _ -> failwith ("Resource file not found : " ^ file)
  841.                 | _ -> failwith ("Resource '" ^ file ^ "' excess the maximum size of 12MB")
  842.             ) in
  843.             if Hashtbl.mem com.resources name then failwith ("Duplicate resource name " ^ name);
  844.             Hashtbl.add com.resources name data
  845.         ),"<file>[@name] : add a named resource file");
  846.         ("-prompt", Arg.Unit (fun() -> prompt := true),": prompt on error");
  847.         ("-cmd", Arg.String (fun cmd ->
  848.             cmds := unquote cmd :: !cmds
  849.         ),": run the specified command after successful compilation");
  850.         ("--flash-strict", define Define.FlashStrict, ": more type strict flash API");
  851.         ("--no-traces", define Define.NoTraces, ": don't compile trace calls in the program");
  852.         ("--gen-hx-classes", Arg.Unit (fun() ->
  853.             force_typing := true;
  854.             pre_compilation := (fun() ->
  855.                 List.iter (fun (_,_,extract) ->
  856.                     Hashtbl.iter (fun n _ -> classes := n :: !classes) (extract())
  857.                 ) com.swf_libs;
  858.             ) :: !pre_compilation;
  859.             xml_out := Some "hx"
  860.         ),": generate hx headers for all input classes");
  861.         ("--next", Arg.Unit (fun() -> assert false), ": separate several haxe compilations");
  862.         ("--display", Arg.String (fun file_pos ->
  863.             match file_pos with
  864.             | "classes" ->
  865.                 pre_compilation := (fun() -> raise (Parser.TypePath (["."],None))) :: !pre_compilation;
  866.             | "keywords" ->
  867.                 complete_fields (Hashtbl.fold (fun k _ acc -> (k,"","") :: acc) Lexer.keywords [])
  868.             | _ ->
  869.                 let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in
  870.                 let file = unquote file in
  871.                 let pos = try int_of_string pos with _ -> failwith ("Invalid format : "  ^ pos) in
  872.                 com.display <- true;
  873.                 Common.display_default := true;
  874.                 Common.define com Define.Display;
  875.                 Parser.use_doc := true;
  876.                 Parser.resume_display := {
  877.                     Ast.pfile = Common.unique_full_path file;
  878.                     Ast.pmin = pos;
  879.                     Ast.pmax = pos;
  880.                 };
  881.         ),": display code tips");
  882.         ("--no-output", Arg.Unit (fun() -> no_output := true),": compiles but does not generate any file");
  883.         ("--times", Arg.Unit (fun() -> measure_times := true),": measure compilation times");
  884.         ("--no-inline", define Define.NoInline, ": disable inlining");
  885.         ("--no-opt", Arg.Unit (fun() ->
  886.             com.foptimize <- false;
  887.             Common.define com Define.NoOpt;
  888.         ), ": disable code optimizations");
  889.         ("--js-modern", Arg.Unit (fun() ->
  890.             Common.define com Define.JsModern;
  891.         ), ": wrap JS output in a closure, strict mode, and other upcoming features");
  892.         ("--php-front",Arg.String (fun f ->
  893.             if com.php_front <> None then raise (Arg.Bad "Multiple --php-front");
  894.             com.php_front <- Some f;
  895.         ),"<filename> : select the name for the php front file");
  896.         ("--php-lib",Arg.String (fun f ->
  897.             if com.php_lib <> None then raise (Arg.Bad "Multiple --php-lib");
  898.             com.php_lib <- Some f;
  899.         ),"<filename> : select the name for the php lib folder");
  900.         ("--php-prefix", Arg.String (fun f ->
  901.             if com.php_prefix <> None then raise (Arg.Bad "Multiple --php-prefix");
  902.             com.php_prefix <- Some f;
  903.             Common.define com Define.PhpPrefix;
  904.         ),"<name> : prefix all classes with given name");
  905.         ("--remap", Arg.String (fun s ->
  906.             let pack, target = (try ExtString.String.split s ":" with _ -> raise (Arg.Bad "Invalid format")) in
  907.             com.package_rules <- PMap.add pack (Remap target) com.package_rules;
  908.         ),"<package:target> : remap a package to another one");
  909.         ("--interp", Arg.Unit (fun() ->
  910.             Common.define com Define.Interp;
  911.             set_platform Neko "";
  912.             no_output := true;
  913.             interp := true;
  914.         ),": interpret the program using internal macro system");
  915.         ("--macro", Arg.String (fun e ->
  916.             force_typing := true;
  917.             config_macros := e :: !config_macros
  918.         )," : call the given macro before typing anything else");
  919.         ("--dce", Arg.String (fun mode ->
  920.             (match mode with
  921.             | "std" | "full" | "no" -> ()
  922.             | _ -> raise (Arg.Bad "Invalid DCE mode"));
  923.             Common.define_value com Define.Dce mode
  924.         ),"[std|full|no] : set the dead code elimination mode");
  925.         ("--wait", Arg.String (fun hp ->
  926.             let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
  927.             wait_loop com host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port"))
  928.         ),"<[host:]port> : wait on the given port for commands to run)");
  929.         ("--connect",Arg.String (fun _ ->
  930.             assert false
  931.         ),"<[host:]port> : connect on the given port and run commands there)");
  932.         ("--cwd", Arg.String (fun dir ->
  933.             (try Unix.chdir dir with _ -> raise (Arg.Bad "Invalid directory"))
  934.         ),"<dir> : set current working directory");
  935.         ("--help-defines", Arg.Unit (fun() ->
  936.             let rec loop i =
  937.                 let d = Obj.magic i in
  938.                 if d <> Define.Last then begin
  939.                     let t, doc = Define.infos d in
  940.                     message ctx (String.concat "-" (ExtString.String.nsplit t "_") ^ " : " ^ doc) Ast.null_pos;
  941.                     loop (i + 1)
  942.                 end
  943.             in
  944.             loop 0;
  945.             did_something := true
  946.         ),": print help for all compiler specific defines");
  947.         ("-swf9",Arg.String (fun file ->
  948.             set_platform Flash file;
  949.         ),"<file> : [deprecated] compile code to Flash9 SWF file");
  950.     ] in
  951.     let args_callback cl = classes := make_path cl :: !classes in
  952.     let process args =
  953.         let current = ref 0 in
  954.         Arg.parse_argv ~current (Array.of_list ("" :: List.map expand_env args)) (basic_args_spec @ adv_args_spec) args_callback usage
  955.     in
  956.     process ctx.com.args;
  957.     let rec loop() =
  958.         extra_args := !extra_args @ add_libs com (!cp_libs);
  959.         cp_libs := [];
  960.         match !extra_args with
  961.         | [] -> ()
  962.         | l ->
  963.             extra_args := [];
  964.             process l;
  965.             loop()
  966.     in
  967.     loop();
  968.     (try ignore(Common.find_file com "mt/Include.hx"); Common.raw_define com "mt"; with Not_found -> ());
  969.     if com.display then begin
  970.         com.warning <- message ctx;
  971.         com.error <- error ctx;
  972.         com.main_class <- None;
  973.         let real = Extc.get_real_path (!Parser.resume_display).Ast.pfile in
  974.         classes := lookup_classes com real;
  975.         Common.log com ("Display file : " ^ real);
  976.         Common.log com ("Classes found : ["  ^ (String.concat "," (List.map Ast.s_type_path !classes)) ^ "]");
  977.     end;
  978.     let add_std dir =
  979.         com.class_path <- List.filter (fun s -> not (List.mem s com.std_path)) com.class_path @ List.map (fun p -> p ^ dir ^ "/_std/") com.std_path @ com.std_path
  980.     in
  981.     let ext = (match com.platform with
  982.         | Cross ->
  983.             (* no platform selected *)
  984.             set_platform Cross "";
  985.             "?"
  986.         | Flash8 | Flash ->
  987.             if com.flash_version >= 9. then begin
  988.                 let rec loop = function
  989.                     | [] -> ()
  990.                     | (v,_) :: _ when v > com.flash_version -> ()
  991.                     | (v,def) :: l ->
  992.                         Common.raw_define com ("flash" ^ def);
  993.                         loop l
  994.                 in
  995.                 loop Common.flash_versions;
  996.                 Common.raw_define com "flash";
  997.                 com.defines <- PMap.remove "flash8" com.defines;
  998.                 com.package_rules <- PMap.remove "flash" com.package_rules;
  999.                 add_std "flash";
  1000.             end else begin
  1001.                 com.package_rules <- PMap.add "flash" (Directory "flash8") com.package_rules;
  1002.                 com.package_rules <- PMap.add "flash8" Forbidden com.package_rules;
  1003.                 Common.raw_define com "flash";
  1004.                 Common.raw_define com ("flash" ^ string_of_int (int_of_float com.flash_version));
  1005.                 com.platform <- Flash8;
  1006.                 add_std "flash8";
  1007.             end;
  1008.             "swf"
  1009.         | Neko ->
  1010.             add_std "neko";
  1011.             "n"
  1012.         | Js ->
  1013.             add_std "js";
  1014.             "js"
  1015.         | Php ->
  1016.             add_std "php";
  1017.             "php"
  1018.         | Cpp ->
  1019.             add_std "cpp";
  1020.             "cpp"
  1021.         | Cs ->
  1022.             Gencs.before_generate com;
  1023.             add_std "cs"; "cs"
  1024.         | Java ->
  1025.             Genjava.before_generate com;
  1026.             add_std "java"; "java"
  1027.     ) in
  1028.     (* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *)
  1029.     if com.display && not ctx.has_next then com.package_rules <- PMap.foldi (fun p r acc -> match r with Forbidden -> acc | _ -> PMap.add p r acc) com.package_rules PMap.empty;
  1030.     com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
  1031.  
  1032.     (* check file extension. In case of wrong commandline, we don't want
  1033.         to accidentaly delete a source file. *)
  1034.     if not !no_output && file_extension com.file = ext then delete_file com.file;
  1035.     List.iter (fun f -> f()) (List.rev (!pre_compilation));
  1036.     if !classes = [([],"Std")] && not !force_typing then begin
  1037.         if !cmds = [] && not !did_something then Arg.usage basic_args_spec usage;
  1038.     end else begin
  1039.         ctx.setup();
  1040.         Common.log com ("Classpath : " ^ (String.concat ";" com.class_path));
  1041.         Common.log com ("Defines : " ^ (String.concat ";" (PMap.foldi (fun v _ acc -> v :: acc) com.defines [])));
  1042.         let t = Common.timer "typing" in
  1043.         Typecore.type_expr_ref := (fun ctx e need_val -> Typer.type_expr ~need_val ctx e);
  1044.         let tctx = Typer.create com in
  1045.         List.iter (Typer.call_init_macro tctx) (List.rev !config_macros);
  1046.         List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath Ast.null_pos)) (List.rev !classes);
  1047.         Typer.finalize tctx;
  1048.         t();
  1049.         if ctx.has_error then raise Abort;
  1050.         if com.display then begin
  1051.             if ctx.has_next then raise Abort;
  1052.             failwith "No completion point was found";
  1053.         end;
  1054.         let t = Common.timer "filters" in
  1055.         let main, types, modules = Typer.generate tctx in
  1056.         com.main <- main;
  1057.         com.types <- types;
  1058.         com.modules <- modules;
  1059.         let filters = [
  1060.             if com.foptimize then Optimizer.reduce_expression tctx else Optimizer.sanitize tctx;
  1061.             Codegen.check_local_vars_init;
  1062.             Codegen.captured_vars com;
  1063.             Codegen.rename_local_vars com;
  1064.         ] in
  1065.         List.iter (Codegen.post_process filters) com.types;
  1066.         Codegen.post_process_end();
  1067.         List.iter (fun f -> f()) (List.rev com.filters);
  1068.         List.iter (Codegen.save_class_state tctx) com.types;
  1069.         let dce_mode = (try Common.defined_value com Define.Dce with _ -> "no") in
  1070.         if not (!gen_as3 || dce_mode = "no" || Common.defined com Define.DocGen) then Dce.run com main (dce_mode = "full" && not !interp);
  1071.         let type_filters = [
  1072.             Codegen.check_private_path;
  1073.             Codegen.remove_generic_base;
  1074.             Codegen.apply_native_paths;
  1075.             Codegen.add_rtti;
  1076.             Codegen.remove_extern_fields;
  1077.             Codegen.add_field_inits;
  1078.             Codegen.add_meta_field;
  1079.             Codegen.check_remove_metadata;
  1080.         ] in
  1081.         List.iter (fun t -> List.iter (fun f -> f tctx t) type_filters) com.types;
  1082.         if ctx.has_error then raise Abort;
  1083.         (match !xml_out with
  1084.         | None -> ()
  1085.         | Some "hx" ->
  1086.             Genxml.generate_hx com
  1087.         | Some file ->
  1088.             Common.log com ("Generating xml : " ^ file);
  1089.             Genxml.generate com file);
  1090.         if com.platform = Flash || com.platform = Cpp || com.platform = Cs then List.iter (Codegen.fix_overrides com) com.types;
  1091.         if Common.defined com Define.Dump then Codegen.dump_types com;
  1092.         if Common.defined com Define.DumpDependencies then Codegen.dump_dependencies com;
  1093.         t();
  1094.         (match com.platform with
  1095.         | _ when !no_output ->
  1096.             if !interp then begin
  1097.                 let ctx = Interp.create com (Typer.make_macro_api tctx Ast.null_pos) in
  1098.                 Interp.add_types ctx com.types (fun t -> ());
  1099.                 (match com.main with
  1100.                 | None -> ()
  1101.                 | Some e -> ignore(Interp.eval_expr ctx e));
  1102.             end;
  1103.         | Cross ->
  1104.             ()
  1105.         | Flash8 | Flash when !gen_as3 ->
  1106.             Common.log com ("Generating AS3 in : " ^ com.file);
  1107.             Genas3.generate com;
  1108.         | Flash8 | Flash ->
  1109.             Common.log com ("Generating swf : " ^ com.file);
  1110.             Genswf.generate com !swf_header;
  1111.         | Neko ->
  1112.             Common.log com ("Generating neko : " ^ com.file);
  1113.             Genneko.generate com;
  1114.         | Js ->
  1115.             Common.log com ("Generating js : " ^ com.file);
  1116.             Genjs.generate com
  1117.         | Php ->
  1118.             Common.log com ("Generating PHP in : " ^ com.file);
  1119.             Genphp.generate com;
  1120.         | Cpp ->
  1121.             Common.log com ("Generating Cpp in : " ^ com.file);
  1122.             Gencpp.generate com;
  1123.         | Cs ->
  1124.             if com.verbose then print_endline ("Generating C# in : " ^ com.file);
  1125.             Gencs.generate com;
  1126.         | Java ->
  1127.             if com.verbose then print_endline ("Generating Java in : " ^ com.file);
  1128.             Genjava.generate com;
  1129.         );
  1130.     end;
  1131.     Sys.catch_break false;
  1132.     if not !no_output then List.iter (run_command ctx) (List.rev !cmds)
  1133. with
  1134.     | Abort | Typecore.Fatal_error ->
  1135.         ()
  1136.     | Common.Abort (m,p) ->
  1137.         error ctx m p
  1138.     | Lexer.Error (m,p) ->
  1139.         error ctx (Lexer.error_msg m) p
  1140.     | Parser.Error (m,p) ->
  1141.         error ctx (Parser.error_msg m) p
  1142.     | Typecore.Forbid_package ((pack,m,p),pl,pf)  ->
  1143.         if !Common.display_default && ctx.has_next then
  1144.             ()
  1145.         else begin
  1146.             error ctx (Printf.sprintf "You cannot access the %s package while %s (for %s)" pack (if pf = "macro" then "in a macro" else "targeting " ^ pf) (Ast.s_type_path m) ) p;
  1147.             List.iter (error ctx "    referenced here") (List.rev pl);
  1148.         end
  1149.     | Typecore.Error (m,p) ->
  1150.         error ctx (Typecore.error_msg m) p
  1151.     | Interp.Error (msg,p :: l) ->
  1152.         message ctx msg p;
  1153.         List.iter (message ctx "Called from") l;
  1154.         error ctx "Aborted" Ast.null_pos;
  1155.     | Failure msg | Arg.Bad msg ->
  1156.         error ctx ("Error : " ^ msg) Ast.null_pos
  1157.     | Arg.Help msg ->
  1158.         message ctx msg Ast.null_pos
  1159.     | Typer.DisplayFields fields ->
  1160.         let ctx = print_context() in
  1161.         let fields = List.map (fun (name,t,doc) -> name, s_type ctx t, (match doc with None -> "" | Some d -> d)) fields in
  1162.         let fields = if !measure_times then begin
  1163.             close_times();
  1164.             let tot = ref 0. in
  1165.             Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
  1166.             let fields = ("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. !start_time), "") :: fields in
  1167.             if !tot > 0. then
  1168.                 Hashtbl.fold (fun _ t acc ->
  1169.                     ("@TIME " ^ t.name, Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot), "") :: acc
  1170.                 ) Common.htimers fields
  1171.             else fields
  1172.         end else
  1173.             fields
  1174.         in
  1175.         complete_fields fields
  1176.     | Typer.DisplayTypes tl ->
  1177.         let ctx = print_context() in
  1178.         let b = Buffer.create 0 in
  1179.         List.iter (fun t ->
  1180.             Buffer.add_string b "<type>\n";
  1181.             Buffer.add_string b (htmlescape (s_type ctx t));
  1182.             Buffer.add_string b "\n</type>\n";
  1183.         ) tl;
  1184.         raise (Completion (Buffer.contents b))
  1185.     | Parser.TypePath (p,c) ->
  1186.         (match c with
  1187.         | None ->
  1188.             let packs, classes = read_type_path com p in
  1189.             if packs = [] && classes = [] then
  1190.                 error ctx ("No classes found in " ^ String.concat "." p) Ast.null_pos
  1191.             else
  1192.                 complete_fields (List.map (fun f -> f,"","") (packs @ classes))
  1193.         | Some (c,cur_package) ->
  1194.             try
  1195.                 let ctx = Typer.create com in
  1196.                 let rec lookup p =
  1197.                     try
  1198.                         Typeload.load_module ctx (p,c) Ast.null_pos
  1199.                     with e ->
  1200.                         if cur_package then
  1201.                             match List.rev p with
  1202.                             | [] -> raise e
  1203.                             | _ :: p -> lookup (List.rev p)
  1204.                         else
  1205.                             raise e
  1206.                 in
  1207.                 let m = lookup p in
  1208.                 complete_fields (List.map (fun t -> snd (t_path t),"","") (List.filter (fun t -> not (t_infos t).mt_private) m.m_types))
  1209.             with Completion c ->
  1210.                 raise (Completion c)
  1211.             | _ ->
  1212.                 error ctx ("Could not load module " ^ (Ast.s_type_path (p,c))) Ast.null_pos)
  1213.     | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || !global_cache <> None with _ -> true) ->
  1214.         error ctx (Printexc.to_string e) Ast.null_pos
  1215.  
  1216. ;;
  1217. let other = Common.timer "other" in
  1218. Sys.catch_break true;
  1219. let args = List.tl (Array.to_list Sys.argv) in
  1220. (try
  1221.     let server = Sys.getenv "HAXE_COMPILATION_SERVER" in
  1222.     let host, port = (try ExtString.String.split server ":" with _ -> "127.0.0.1", server) in
  1223.     do_connect host (try int_of_string port with _ -> failwith "Invalid HAXE_COMPILATION_SERVER port") args
  1224. with Not_found -> try
  1225.     process_params create_context args
  1226. with Completion c ->
  1227.     prerr_endline c;
  1228.     exit 0
  1229. );
  1230. other();
  1231. if !measure_times then report_times prerr_endline
Advertisement
Add Comment
Please, Sign In to add comment