main.ml 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767
  1. (*
  2. * Copyright (C)2005-2013 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. (*
  23. Conventions:
  24. - e: expression (typed or untyped)
  25. - c: class
  26. - en: enum
  27. - td: typedef (tdef)
  28. - a: abstract
  29. - an: anon
  30. - tf: tfunc
  31. - cf: class_field
  32. - ef: enum_field
  33. - t: type (t)
  34. - ct: complex_type
  35. - v: local variable (tvar)
  36. - m: module (module_def)
  37. - mt: module_type
  38. - p: pos
  39. "param" refers to type parameters
  40. "arg" refers to function arguments
  41. leading s_ means function returns string
  42. trailing l means list (but we also use natural plurals such as "metas")
  43. semantic suffixes may be used freely (e.g. e1, e_if, e')
  44. *)
  45. open Printf
  46. open Ast
  47. open Genswf
  48. open Common
  49. open Type
  50. type context = {
  51. com : Common.context;
  52. mutable flush : unit -> unit;
  53. mutable setup : unit -> unit;
  54. mutable messages : string list;
  55. mutable has_next : bool;
  56. mutable has_error : bool;
  57. }
  58. type cache = {
  59. mutable c_haxelib : (string list, string list) Hashtbl.t;
  60. mutable c_files : (string, float * Ast.package) Hashtbl.t;
  61. mutable c_modules : (path * string, module_def) Hashtbl.t;
  62. }
  63. exception Abort
  64. exception Completion of string
  65. let version = 3300
  66. let version_major = version / 1000
  67. let version_minor = (version mod 1000) / 100
  68. let version_revision = (version mod 100)
  69. let version_is_stable = version_minor land 1 = 0
  70. let measure_times = ref false
  71. let prompt = ref false
  72. let start_time = ref (get_time())
  73. let global_cache = ref None
  74. let path_sep = if Sys.os_type = "Unix" then "/" else "\\"
  75. let get_real_path p =
  76. try
  77. Extc.get_real_path p
  78. with _ ->
  79. p
  80. let executable_path() =
  81. Extc.executable_path()
  82. let is_debug_run() =
  83. try Sys.getenv "HAXEDEBUG" = "1" with _ -> false
  84. let s_version =
  85. Printf.sprintf "%d.%d.%d%s" version_major version_minor version_revision (match Version.version_extra with None -> "" | Some v -> " " ^ v)
  86. let format msg p =
  87. if p = Ast.null_pos then
  88. msg
  89. else begin
  90. let error_printer file line = sprintf "%s:%d:" file line in
  91. let epos = Lexer.get_error_pos error_printer p in
  92. let msg = String.concat ("\n" ^ epos ^ " : ") (ExtString.String.nsplit msg "\n") in
  93. sprintf "%s : %s" epos msg
  94. end
  95. let ssend sock str =
  96. let rec loop pos len =
  97. if len = 0 then
  98. ()
  99. else
  100. let s = Unix.send sock str pos len [] in
  101. loop (pos + s) (len - s)
  102. in
  103. loop 0 (String.length str)
  104. let message ctx msg p =
  105. ctx.messages <- format msg p :: ctx.messages
  106. let deprecated = [
  107. "Type not found : IntIter","IntIter was renamed to IntIterator";
  108. "EReg has no field customReplace","EReg.customReplace was renamed to EReg.map";
  109. "#StringTools has no field isEOF","StringTools.isEOF was renamed to StringTools.isEof";
  110. "Type not found : haxe.BaseCode","haxe.BaseCode was moved to haxe.crypto.BaseCode";
  111. "Type not found : haxe.Md5","haxe.Md5 was moved to haxe.crypto.Md5";
  112. "Type not found : haxe.SHA1","haxe.SHA1 was moved to haxe.crypto.SHA1";
  113. "Type not found : Hash","Hash has been removed, use Map instead";
  114. "Type not found : IntHash","IntHash has been removed, use Map instead";
  115. "Type not found : haxe.FastList","haxe.FastList was moved to haxe.ds.GenericStack";
  116. "#Std has no field format","Std.format has been removed, use single quote 'string ${escape}' syntax instead";
  117. "Identifier 'EType' is not part of enum haxe.macro.ExprDef","EType has been removed, use EField instead";
  118. "Identifier 'CType' is not part of enum haxe.macro.Constant","CType has been removed, use CIdent instead";
  119. "Type not found : haxe.rtti.Infos","Use @:rtti instead of implementing haxe.rtti.Infos";
  120. "Type not found : haxe.rtti.Generic","Use @:generic instead of implementing haxe.Generic";
  121. "Type not found : flash.utils.TypedDictionary","flash.utils.TypedDictionary has been removed, use Map instead";
  122. "Type not found : haxe.Stack", "haxe.Stack has been renamed to haxe.CallStack";
  123. "Type not found : neko.zip.Reader", "neko.zip.Reader has been removed, use haxe.zip.Reader instead";
  124. "Type not found : neko.zip.Writer", "neko.zip.Writer has been removed, use haxe.zip.Writer instead";
  125. "Type not found : haxe.Public", "Use @:publicFields instead of implementing or extending haxe.Public";
  126. "#Xml has no field createProlog", "Xml.createProlog was renamed to Xml.createProcessingInstruction"
  127. ]
  128. let limit_string s offset =
  129. let rest = 80 - offset in
  130. let words = ExtString.String.nsplit s " " in
  131. let rec loop i words = match words with
  132. | word :: words ->
  133. if String.length word + i + 1 > rest then (Printf.sprintf "\n%*s" offset "") :: word :: loop (String.length word) words
  134. else (if i = 0 then "" else " ") :: word :: loop (i + 1 + String.length word) words
  135. | [] ->
  136. []
  137. in
  138. String.concat "" (loop 0 words)
  139. let error ctx msg p =
  140. let msg = try List.assoc msg deprecated with Not_found -> msg in
  141. message ctx msg p;
  142. ctx.has_error <- true
  143. let htmlescape s =
  144. let s = String.concat "&amp;" (ExtString.String.nsplit s "&") in
  145. let s = String.concat "&lt;" (ExtString.String.nsplit s "<") in
  146. let s = String.concat "&gt;" (ExtString.String.nsplit s ">") in
  147. s
  148. let reserved_flags = [
  149. "cross";"js";"neko";"flash";"php";"cpp";"cs";"java";"python";
  150. "as3";"swc";"macro";"sys"
  151. ]
  152. let complete_fields com fields =
  153. let b = Buffer.create 0 in
  154. let details = Common.raw_defined com "display-details" in
  155. Buffer.add_string b "<list>\n";
  156. List.iter (fun (n,t,k,d) ->
  157. let s_kind = match k with
  158. | Some k -> (match k with
  159. | Typer.FKVar -> "var"
  160. | Typer.FKMethod -> "method"
  161. | Typer.FKType -> "type"
  162. | Typer.FKPackage -> "package")
  163. | None -> ""
  164. in
  165. if details then
  166. Buffer.add_string b (Printf.sprintf "<i n=\"%s\" k=\"%s\"><t>%s</t><d>%s</d></i>\n" n s_kind (htmlescape t) (htmlescape d))
  167. else
  168. Buffer.add_string b (Printf.sprintf "<i n=\"%s\"><t>%s</t><d>%s</d></i>\n" n (htmlescape t) (htmlescape d))
  169. ) (List.sort (fun (a,_,ak,_) (b,_,bk,_) -> compare (ak,a) (bk,b)) fields);
  170. Buffer.add_string b "</list>\n";
  171. raise (Completion (Buffer.contents b))
  172. let report_times print =
  173. let tot = ref 0. in
  174. Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
  175. print (Printf.sprintf "Total time : %.3fs" !tot);
  176. if !tot > 0. then begin
  177. print "------------------------------------";
  178. let timers = List.sort (fun t1 t2 -> compare t1.name t2.name) (Hashtbl.fold (fun _ t acc -> t :: acc) Common.htimers []) in
  179. List.iter (fun t -> print (Printf.sprintf " %s : %.3fs, %.0f%%" t.name t.total (t.total *. 100. /. !tot))) timers
  180. end
  181. let make_path f =
  182. let f = String.concat "/" (ExtString.String.nsplit f "\\") in
  183. let cl = ExtString.String.nsplit f "." in
  184. let cl = (match List.rev cl with
  185. | ["hx";path] -> ExtString.String.nsplit path "/"
  186. | _ -> cl
  187. ) in
  188. let error msg =
  189. let msg = "Could not process argument " ^ f ^ "\n" ^ msg in
  190. failwith msg
  191. in
  192. let invalid_char x =
  193. for i = 1 to String.length x - 1 do
  194. match x.[i] with
  195. | 'A'..'Z' | 'a'..'z' | '0'..'9' | '_' -> ()
  196. | c -> error ("invalid character: " ^ (String.make 1 c))
  197. done
  198. in
  199. let rec loop = function
  200. | [] ->
  201. error "empty part"
  202. | [x] ->
  203. invalid_char x;
  204. [],x
  205. | x :: l ->
  206. if String.length x = 0 then
  207. error "empty part"
  208. else if x.[0] < 'a' || x.[0] > 'z' then
  209. error "Package name must start with a lower case character";
  210. invalid_char x;
  211. let path,name = loop l in
  212. x :: path,name
  213. in
  214. loop cl
  215. let starts_uppercase x =
  216. x.[0] = '_' || (x.[0] >= 'A' && x.[0] <= 'Z')
  217. let check_uppercase x =
  218. if String.length x = 0 then
  219. failwith "empty part"
  220. else if not (starts_uppercase x) then
  221. failwith "Class name must start with uppercase character"
  222. let make_type_path f =
  223. let pack,name = make_path f in
  224. check_uppercase name;
  225. pack,name
  226. let unique l =
  227. let rec _unique = function
  228. | [] -> []
  229. | x1 :: x2 :: l when x1 = x2 -> _unique (x2 :: l)
  230. | x :: l -> x :: _unique l
  231. in
  232. _unique (List.sort compare l)
  233. let rec read_type_path com p =
  234. let classes = ref [] in
  235. let packages = ref [] in
  236. let p = (match p with
  237. | x :: l ->
  238. (try
  239. match PMap.find x com.package_rules with
  240. | Directory d -> d :: l
  241. | Remap s -> s :: l
  242. | _ -> p
  243. with
  244. Not_found -> p)
  245. | _ -> p
  246. ) in
  247. List.iter (fun path ->
  248. let dir = path ^ String.concat "/" p in
  249. let r = (try Sys.readdir dir with _ -> [||]) in
  250. Array.iter (fun f ->
  251. if (try (Unix.stat (dir ^ "/" ^ f)).Unix.st_kind = Unix.S_DIR with _ -> false) then begin
  252. if f.[0] >= 'a' && f.[0] <= 'z' then begin
  253. if p = ["."] then
  254. match read_type_path com [f] with
  255. | [] , [] -> ()
  256. | _ ->
  257. try
  258. match PMap.find f com.package_rules with
  259. | Forbidden -> ()
  260. | Remap f -> packages := f :: !packages
  261. | Directory _ -> raise Not_found
  262. with Not_found ->
  263. packages := f :: !packages
  264. else
  265. packages := f :: !packages
  266. end;
  267. end else if file_extension f = "hx" then begin
  268. let c = Filename.chop_extension f in
  269. if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
  270. end;
  271. ) r;
  272. ) com.class_path;
  273. List.iter (fun (_,_,extract) ->
  274. Hashtbl.iter (fun (path,name) _ ->
  275. if path = p then classes := name :: !classes else
  276. let rec loop p1 p2 =
  277. match p1, p2 with
  278. | [], _ -> ()
  279. | x :: _, [] -> packages := x :: !packages
  280. | a :: p1, b :: p2 -> if a = b then loop p1 p2
  281. in
  282. loop path p
  283. ) (extract());
  284. ) com.swf_libs;
  285. List.iter (fun (path,std,close,all_files,lookup) ->
  286. List.iter (fun (path, name) ->
  287. if path = p then classes := name :: !classes else
  288. let rec loop p1 p2 =
  289. match p1, p2 with
  290. | [], _ -> ()
  291. | x :: _, [] -> packages := x :: !packages
  292. | a :: p1, b :: p2 -> if a = b then loop p1 p2
  293. in
  294. loop path p
  295. ) (all_files())
  296. ) com.java_libs;
  297. List.iter (fun (path,std,all_files,lookup) ->
  298. List.iter (fun (path, name) ->
  299. if path = p then classes := name :: !classes else
  300. let rec loop p1 p2 =
  301. match p1, p2 with
  302. | [], _ -> ()
  303. | x :: _, [] -> packages := x :: !packages
  304. | a :: p1, b :: p2 -> if a = b then loop p1 p2
  305. in
  306. loop path p
  307. ) (all_files())
  308. ) com.net_libs;
  309. unique !packages, unique !classes
  310. let delete_file f = try Sys.remove f with _ -> ()
  311. let expand_env ?(h=None) path =
  312. let r = Str.regexp "%\\([A-Za-z0-9_]+\\)%" in
  313. Str.global_substitute r (fun s ->
  314. let key = Str.matched_group 1 s in
  315. try
  316. Sys.getenv key
  317. with Not_found -> try
  318. match h with
  319. | None -> raise Not_found
  320. | Some h -> Hashtbl.find h key
  321. with Not_found ->
  322. "%" ^ key ^ "%"
  323. ) path
  324. let unquote v =
  325. let len = String.length v in
  326. if len > 0 && v.[0] = '"' && v.[len - 1] = '"' then String.sub v 1 (len - 2) else v
  327. let parse_hxml_data data =
  328. let lines = Str.split (Str.regexp "[\r\n]+") data in
  329. List.concat (List.map (fun l ->
  330. let l = unquote (ExtString.String.strip l) in
  331. if l = "" || l.[0] = '#' then
  332. []
  333. else if l.[0] = '-' then
  334. try
  335. let a, b = ExtString.String.split l " " in
  336. [unquote a; unquote (ExtString.String.strip b)]
  337. with
  338. _ -> [l]
  339. else
  340. [l]
  341. ) lines)
  342. let parse_hxml file =
  343. let ch = IO.input_channel (try open_in_bin file with _ -> raise Not_found) in
  344. let data = IO.read_all ch in
  345. IO.close_in ch;
  346. parse_hxml_data data
  347. let lookup_classes com spath =
  348. let rec loop = function
  349. | [] -> []
  350. | cp :: l ->
  351. let cp = (if cp = "" then "./" else cp) in
  352. let c = normalize_path (get_real_path (Common.unique_full_path cp)) in
  353. let clen = String.length c in
  354. if clen < String.length spath && String.sub spath 0 clen = c then begin
  355. let path = String.sub spath clen (String.length spath - clen) in
  356. (try
  357. let path = make_type_path path in
  358. (match loop l with
  359. | [x] when String.length (Ast.s_type_path x) < String.length (Ast.s_type_path path) -> [x]
  360. | _ -> [path])
  361. with _ -> loop l)
  362. end else
  363. loop l
  364. in
  365. loop com.class_path
  366. let add_libs com libs =
  367. let call_haxelib() =
  368. let t = Common.timer "haxelib" in
  369. let cmd = "haxelib path " ^ String.concat " " libs in
  370. let pin, pout, perr = Unix.open_process_full cmd (Unix.environment()) in
  371. let lines = Std.input_list pin in
  372. let err = Std.input_list perr in
  373. let ret = Unix.close_process_full (pin,pout,perr) in
  374. if ret <> Unix.WEXITED 0 then failwith (match lines, err with
  375. | [], [] -> "Failed to call haxelib (command not found ?)"
  376. | [], [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"
  377. | _ -> String.concat "\n" (lines@err));
  378. t();
  379. lines
  380. in
  381. match libs with
  382. | [] -> []
  383. | _ ->
  384. let lines = match !global_cache with
  385. | Some cache ->
  386. (try
  387. (* if we are compiling, really call haxelib since library path might have changed *)
  388. if com.display = DMNone then raise Not_found;
  389. Hashtbl.find cache.c_haxelib libs
  390. with Not_found ->
  391. let lines = call_haxelib() in
  392. Hashtbl.replace cache.c_haxelib libs lines;
  393. lines)
  394. | _ -> call_haxelib()
  395. in
  396. let extra_args = ref [] in
  397. let lines = List.fold_left (fun acc l ->
  398. let l = ExtString.String.strip l in
  399. if l = "" then acc else
  400. if l.[0] <> '-' then l :: acc else
  401. match (try ExtString.String.split l " " with _ -> l, "") with
  402. | ("-L",dir) ->
  403. com.neko_libs <- String.sub l 3 (String.length l - 3) :: com.neko_libs;
  404. acc
  405. | param, value ->
  406. extra_args := param :: !extra_args;
  407. if value <> "" then extra_args := value :: !extra_args;
  408. acc
  409. ) [] lines in
  410. com.class_path <- lines @ com.class_path;
  411. List.rev !extra_args
  412. let run_command ctx cmd =
  413. let h = Hashtbl.create 0 in
  414. Hashtbl.add h "__file__" ctx.com.file;
  415. Hashtbl.add h "__platform__" (platform_name ctx.com.platform);
  416. let t = Common.timer "command" in
  417. let cmd = expand_env ~h:(Some h) cmd in
  418. let len = String.length cmd in
  419. if len > 3 && String.sub cmd 0 3 = "cd " then begin
  420. Sys.chdir (String.sub cmd 3 (len - 3));
  421. 0
  422. end else
  423. let binary_string s =
  424. if Sys.os_type <> "Win32" && Sys.os_type <> "Cygwin" then s else String.concat "\n" (Str.split (Str.regexp "\r\n") s)
  425. in
  426. let pout, pin, perr = Unix.open_process_full cmd (Unix.environment()) in
  427. let iout = Unix.descr_of_in_channel pout in
  428. let ierr = Unix.descr_of_in_channel perr in
  429. let berr = Buffer.create 0 in
  430. let bout = Buffer.create 0 in
  431. let tmp = String.create 1024 in
  432. let result = ref None in
  433. (*
  434. we need to read available content on process out/err if we want to prevent
  435. the process from blocking when the pipe is full
  436. *)
  437. let is_process_running() =
  438. let pid, r = Unix.waitpid [Unix.WNOHANG] (-1) in
  439. if pid = 0 then
  440. true
  441. else begin
  442. result := Some r;
  443. false;
  444. end
  445. in
  446. let rec loop ins =
  447. let (ch,_,_), timeout = (try Unix.select ins [] [] 0.02, true with _ -> ([],[],[]),false) in
  448. match ch with
  449. | [] ->
  450. (* make sure we read all *)
  451. if timeout && is_process_running() then
  452. loop ins
  453. else begin
  454. Buffer.add_string berr (IO.read_all (IO.input_channel perr));
  455. Buffer.add_string bout (IO.read_all (IO.input_channel pout));
  456. end
  457. | s :: _ ->
  458. let n = Unix.read s tmp 0 (String.length tmp) in
  459. if s == iout && n > 0 then
  460. ctx.com.print (String.sub tmp 0 n)
  461. else
  462. Buffer.add_substring (if s == iout then bout else berr) tmp 0 n;
  463. loop (if n = 0 then List.filter ((!=) s) ins else ins)
  464. in
  465. (try loop [iout;ierr] with Unix.Unix_error _ -> ());
  466. let serr = binary_string (Buffer.contents berr) in
  467. let sout = binary_string (Buffer.contents bout) in
  468. 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;
  469. if sout <> "" then ctx.com.print sout;
  470. let r = (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
  471. | Unix.WEXITED e -> e
  472. | Unix.WSIGNALED s | Unix.WSTOPPED s -> if s = 0 then -1 else s
  473. ) in
  474. t();
  475. r
  476. let display_memory ctx =
  477. let verbose = ctx.com.verbose in
  478. let print = print_endline in
  479. let fmt_size sz =
  480. if sz < 1024 then
  481. string_of_int sz ^ " B"
  482. else if sz < 1024*1024 then
  483. string_of_int (sz asr 10) ^ " KB"
  484. else
  485. Printf.sprintf "%.1f MB" ((float_of_int sz) /. (1024.*.1024.))
  486. in
  487. let size v =
  488. fmt_size (mem_size v)
  489. in
  490. Gc.full_major();
  491. Gc.compact();
  492. let mem = Gc.stat() in
  493. print ("Total Allocated Memory " ^ fmt_size (mem.Gc.heap_words * (Sys.word_size asr 8)));
  494. print ("Free Memory " ^ fmt_size (mem.Gc.free_words * (Sys.word_size asr 8)));
  495. (match !global_cache with
  496. | None ->
  497. print "No cache found";
  498. | Some c ->
  499. print ("Total cache size " ^ size c);
  500. print (" haxelib " ^ size c.c_haxelib);
  501. print (" parsed ast " ^ size c.c_files ^ " (" ^ string_of_int (Hashtbl.length c.c_files) ^ " files stored)");
  502. print (" typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)");
  503. let rec scan_module_deps m h =
  504. if Hashtbl.mem h m.m_id then
  505. ()
  506. else begin
  507. Hashtbl.add h m.m_id m;
  508. PMap.iter (fun _ m -> scan_module_deps m h) m.m_extra.m_deps
  509. end
  510. in
  511. let all_modules = Hashtbl.fold (fun _ m acc -> PMap.add m.m_id m acc) c.c_modules PMap.empty in
  512. let modules = Hashtbl.fold (fun (path,key) m acc ->
  513. let mdeps = Hashtbl.create 0 in
  514. scan_module_deps m mdeps;
  515. let deps = ref [] in
  516. let out = ref all_modules in
  517. Hashtbl.iter (fun _ md ->
  518. out := PMap.remove md.m_id !out;
  519. if m == md then () else begin
  520. deps := Obj.repr md :: !deps;
  521. List.iter (fun t ->
  522. match t with
  523. | TClassDecl c ->
  524. deps := Obj.repr c :: !deps;
  525. List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_statics;
  526. List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_fields;
  527. | TEnumDecl e ->
  528. deps := Obj.repr e :: !deps;
  529. List.iter (fun n -> deps := Obj.repr (PMap.find n e.e_constrs) :: !deps) e.e_names;
  530. | TTypeDecl t -> deps := Obj.repr t :: !deps;
  531. | TAbstractDecl a -> deps := Obj.repr a :: !deps;
  532. ) md.m_types;
  533. end
  534. ) mdeps;
  535. let chk = Obj.repr Common.memory_marker :: PMap.fold (fun m acc -> Obj.repr m :: acc) !out [] in
  536. let inf = Objsize.objsize m !deps chk in
  537. (m,Objsize.size_with_headers inf, (inf.Objsize.reached,!deps,!out)) :: acc
  538. ) c.c_modules [] in
  539. let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in
  540. List.iter (fun (m,size,(reached,deps,out)) ->
  541. let key = m.m_extra.m_sign in
  542. if key <> !cur_key then begin
  543. print (Printf.sprintf (" --- CONFIG %s ----------------------------") (Digest.to_hex key));
  544. cur_key := key;
  545. end;
  546. let sign md =
  547. if md.m_extra.m_sign = key then "" else "(" ^ (try Digest.to_hex md.m_extra.m_sign with _ -> "???" ^ md.m_extra.m_sign) ^ ")"
  548. in
  549. print (Printf.sprintf " %s : %s" (Ast.s_type_path m.m_path) (fmt_size size));
  550. (if reached then try
  551. incr mcount;
  552. let lcount = ref 0 in
  553. let leak l =
  554. incr lcount;
  555. incr tcount;
  556. print (Printf.sprintf " LEAK %s" l);
  557. if !lcount >= 3 && !tcount >= 100 && not verbose then begin
  558. print (Printf.sprintf " ...");
  559. raise Exit;
  560. end;
  561. in
  562. if (Objsize.objsize m deps [Obj.repr Common.memory_marker]).Objsize.reached then leak "common";
  563. PMap.iter (fun _ md ->
  564. if (Objsize.objsize m deps [Obj.repr md]).Objsize.reached then leak (Ast.s_type_path md.m_path ^ sign md);
  565. ) out;
  566. with Exit ->
  567. ());
  568. if verbose then begin
  569. print (Printf.sprintf " %d total deps" (List.length deps));
  570. PMap.iter (fun _ md ->
  571. print (Printf.sprintf " dep %s%s" (Ast.s_type_path md.m_path) (sign md));
  572. ) m.m_extra.m_deps;
  573. end;
  574. flush stdout
  575. ) (List.sort (fun (m1,s1,_) (m2,s2,_) ->
  576. let k1 = m1.m_extra.m_sign and k2 = m2.m_extra.m_sign in
  577. if k1 = k2 then s1 - s2 else if k1 > k2 then 1 else -1
  578. ) modules);
  579. if !mcount > 0 then print ("*** " ^ string_of_int !mcount ^ " modules have leaks !");
  580. print "Cache dump complete")
  581. let default_flush ctx =
  582. List.iter prerr_endline (List.rev ctx.messages);
  583. if ctx.has_error && !prompt then begin
  584. print_endline "Press enter to exit...";
  585. ignore(read_line());
  586. end;
  587. if ctx.has_error then exit 1
  588. let create_context params =
  589. let ctx = {
  590. com = Common.create version params;
  591. flush = (fun()->());
  592. setup = (fun()->());
  593. messages = [];
  594. has_next = false;
  595. has_error = false;
  596. } in
  597. ctx.flush <- (fun() -> default_flush ctx);
  598. ctx
  599. let rec process_params create pl =
  600. let each_params = ref [] in
  601. let rec loop acc = function
  602. | [] ->
  603. let ctx = create (!each_params @ (List.rev acc)) in
  604. init ctx;
  605. ctx.flush()
  606. | "--next" :: l when acc = [] -> (* skip empty --next *)
  607. loop [] l
  608. | "--next" :: l ->
  609. let ctx = create (!each_params @ (List.rev acc)) in
  610. ctx.has_next <- true;
  611. init ctx;
  612. ctx.flush();
  613. loop [] l
  614. | "--each" :: l ->
  615. each_params := List.rev acc;
  616. loop [] l
  617. | "--cwd" :: dir :: l ->
  618. (* we need to change it immediately since it will affect hxml loading *)
  619. (try Unix.chdir dir with _ -> raise (Arg.Bad "Invalid directory"));
  620. loop acc l
  621. | "--connect" :: hp :: l ->
  622. (match !global_cache with
  623. | None ->
  624. let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
  625. do_connect host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port")) ((List.rev acc) @ l)
  626. | Some _ ->
  627. (* already connected : skip *)
  628. loop acc l)
  629. | "--run" :: cl :: args ->
  630. let acc = cl :: "-main" :: "--interp" :: acc in
  631. let ctx = create (!each_params @ (List.rev acc)) in
  632. ctx.com.sys_args <- args;
  633. init ctx;
  634. ctx.flush()
  635. | arg :: l ->
  636. match List.rev (ExtString.String.nsplit arg ".") with
  637. | "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) ->
  638. let acc, l = (try acc, parse_hxml arg @ l with Not_found -> (arg ^ " (file not found)") :: acc, l) in
  639. loop acc l
  640. | _ -> loop (arg :: acc) l
  641. in
  642. (* put --display in front if it was last parameter *)
  643. let pl = (match List.rev pl with
  644. | file :: "--display" :: pl when file <> "memory" -> "--display" :: file :: List.rev pl
  645. | "use_rtti_doc" :: "-D" :: file :: "--display" :: pl -> "--display" :: file :: List.rev pl
  646. | _ -> pl
  647. ) in
  648. loop [] pl
  649. and wait_loop boot_com host port =
  650. let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
  651. (try Unix.setsockopt sock Unix.SO_REUSEADDR true with _ -> ());
  652. (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));
  653. Unix.listen sock 10;
  654. Sys.catch_break false;
  655. let verbose = boot_com.verbose in
  656. let has_parse_error = ref false in
  657. if verbose then print_endline ("Waiting on " ^ host ^ ":" ^ string_of_int port);
  658. let bufsize = 1024 in
  659. let tmp = String.create bufsize in
  660. let cache = {
  661. c_haxelib = Hashtbl.create 0;
  662. c_files = Hashtbl.create 0;
  663. c_modules = Hashtbl.create 0;
  664. } in
  665. global_cache := Some cache;
  666. Typer.macro_enable_cache := true;
  667. Typeload.parse_hook := (fun com2 file p ->
  668. let sign = get_signature com2 in
  669. let ffile = Common.unique_full_path file in
  670. let ftime = file_time ffile in
  671. let fkey = ffile ^ "!" ^ sign in
  672. try
  673. let time, data = Hashtbl.find cache.c_files fkey in
  674. if time <> ftime then raise Not_found;
  675. data
  676. with Not_found ->
  677. has_parse_error := false;
  678. let data = Typeload.parse_file com2 file p in
  679. if verbose then print_endline ("Parsed " ^ ffile);
  680. if not !has_parse_error && ffile <> (!Parser.resume_display).Ast.pfile then Hashtbl.replace cache.c_files fkey (ftime,data);
  681. data
  682. );
  683. let cache_module m =
  684. Hashtbl.replace cache.c_modules (m.m_path,m.m_extra.m_sign) m;
  685. in
  686. let check_module_path com m p =
  687. if m.m_extra.m_file <> Common.unique_full_path (Typeload.resolve_module_file com m.m_path (ref[]) p) then begin
  688. if verbose then print_endline ("Module path " ^ s_type_path m.m_path ^ " has been changed");
  689. raise Not_found;
  690. end
  691. in
  692. let compilation_step = ref 0 in
  693. let compilation_mark = ref 0 in
  694. let mark_loop = ref 0 in
  695. Typeload.type_module_hook := (fun (ctx:Typecore.typer) mpath p ->
  696. let t = Common.timer "module cache check" in
  697. let com2 = ctx.Typecore.com in
  698. let sign = get_signature com2 in
  699. let dep = ref None in
  700. incr mark_loop;
  701. let mark = !mark_loop in
  702. let start_mark = !compilation_mark in
  703. let rec check m =
  704. if m.m_extra.m_dirty then begin
  705. dep := Some m;
  706. false
  707. end else if m.m_extra.m_mark = mark then
  708. true
  709. else try
  710. if m.m_extra.m_mark <= start_mark then begin
  711. (match m.m_extra.m_kind with
  712. | MFake | MSub -> () (* don't get classpath *)
  713. | MExtern ->
  714. (* if we have a file then this will override our extern type *)
  715. let has_file = (try ignore(Typeload.resolve_module_file com2 m.m_path (ref[]) p); true with Not_found -> false) in
  716. if has_file then begin
  717. if verbose then print_endline ("A file is masking the library file " ^ s_type_path m.m_path);
  718. raise Not_found;
  719. end;
  720. let rec loop = function
  721. | [] ->
  722. if verbose then print_endline ("No library file was found for " ^ s_type_path m.m_path);
  723. raise Not_found (* no extern registration *)
  724. | load :: l ->
  725. match load m.m_path p with
  726. | None -> loop l
  727. | Some (file,_) ->
  728. if Common.unique_full_path file <> m.m_extra.m_file then begin
  729. if verbose then print_endline ("Library file was changed for " ^ s_type_path m.m_path);
  730. raise Not_found;
  731. end
  732. in
  733. loop com2.load_extern_type
  734. | MCode -> check_module_path com2 m p
  735. | MMacro when ctx.Typecore.in_macro -> check_module_path com2 m p
  736. | MMacro ->
  737. let _, mctx = Typer.get_macro_context ctx p in
  738. check_module_path mctx.Typecore.com m p
  739. );
  740. if file_time m.m_extra.m_file <> m.m_extra.m_time then begin
  741. if verbose then print_endline ("File " ^ m.m_extra.m_file ^ (if m.m_extra.m_time = -1. then " not cached (macro-in-macro)" else " has been modified"));
  742. if m.m_extra.m_kind = MFake then Hashtbl.remove Typecore.fake_modules m.m_extra.m_file;
  743. raise Not_found;
  744. end;
  745. end;
  746. m.m_extra.m_mark <- mark;
  747. PMap.iter (fun _ m2 -> if not (check m2) then begin dep := Some m2; raise Not_found end) m.m_extra.m_deps;
  748. true
  749. with Not_found ->
  750. m.m_extra.m_dirty <- true;
  751. false
  752. in
  753. let rec add_modules m0 m =
  754. if m.m_extra.m_added < !compilation_step then begin
  755. (match m0.m_extra.m_kind, m.m_extra.m_kind with
  756. | MCode, MMacro | MMacro, MCode ->
  757. (* this was just a dependency to check : do not add to the context *)
  758. ()
  759. | _ ->
  760. if verbose then print_endline ("Reusing cached module " ^ Ast.s_type_path m.m_path);
  761. m.m_extra.m_added <- !compilation_step;
  762. List.iter (fun t ->
  763. match t with
  764. | TClassDecl c -> c.cl_restore()
  765. | TEnumDecl e ->
  766. let rec loop acc = function
  767. | [] -> ()
  768. | (Ast.Meta.RealPath,[Ast.EConst (Ast.String path),_],_) :: l ->
  769. e.e_path <- Ast.parse_path path;
  770. e.e_meta <- (List.rev acc) @ l;
  771. | x :: l -> loop (x::acc) l
  772. in
  773. loop [] e.e_meta
  774. | TAbstractDecl a ->
  775. a.a_meta <- List.filter (fun (m,_,_) -> m <> Ast.Meta.ValueUsed) a.a_meta
  776. | _ -> ()
  777. ) m.m_types;
  778. if m.m_extra.m_kind <> MSub then Typeload.add_module ctx m p;
  779. PMap.iter (Hashtbl.add com2.resources) m.m_extra.m_binded_res;
  780. PMap.iter (fun _ m2 -> add_modules m0 m2) m.m_extra.m_deps);
  781. List.iter (Typer.call_init_macro ctx) m.m_extra.m_macro_calls
  782. end
  783. in
  784. try
  785. let m = Hashtbl.find cache.c_modules (mpath,sign) in
  786. if not (check m) then begin
  787. 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 ^ ")"));
  788. raise Not_found;
  789. end;
  790. add_modules m m;
  791. t();
  792. Some m
  793. with Not_found ->
  794. t();
  795. None
  796. );
  797. let run_count = ref 0 in
  798. while true do
  799. let sin, _ = Unix.accept sock in
  800. let t0 = get_time() in
  801. Unix.set_nonblock sin;
  802. if verbose then print_endline "Client connected";
  803. let b = Buffer.create 0 in
  804. let rec read_loop count =
  805. let r = try
  806. Unix.recv sin tmp 0 bufsize []
  807. with Unix.Unix_error((Unix.EWOULDBLOCK|Unix.EAGAIN),_,_) ->
  808. 0
  809. in
  810. if verbose then begin
  811. if r > 0 then Printf.printf "Reading %d bytes\n" r else print_endline "Waiting for data...";
  812. end;
  813. Buffer.add_substring b tmp 0 r;
  814. if r > 0 && tmp.[r-1] = '\000' then
  815. Buffer.sub b 0 (Buffer.length b - 1)
  816. else begin
  817. if r = 0 then ignore(Unix.select [] [] [] 0.05); (* wait a bit *)
  818. if count = 100 then
  819. failwith "Aborting unactive connection"
  820. else
  821. read_loop (count + 1);
  822. end;
  823. in
  824. let rec cache_context com =
  825. if com.display = DMNone then begin
  826. List.iter cache_module com.modules;
  827. if verbose then print_endline ("Cached " ^ string_of_int (List.length com.modules) ^ " modules");
  828. end;
  829. match com.get_macros() with
  830. | None -> ()
  831. | Some com -> cache_context com
  832. in
  833. let create params =
  834. let ctx = create_context params in
  835. ctx.flush <- (fun() ->
  836. incr compilation_step;
  837. compilation_mark := !mark_loop;
  838. List.iter (fun s -> ssend sin (s ^ "\n"); if verbose then print_endline ("> " ^ s)) (List.rev ctx.messages);
  839. if ctx.has_error then ssend sin "\x02\n" else cache_context ctx.com;
  840. );
  841. ctx.setup <- (fun() ->
  842. Parser.display_error := (fun e p -> has_parse_error := true; ctx.com.error (Parser.error_msg e) p);
  843. if ctx.com.display <> DMNone then begin
  844. let file = (!Parser.resume_display).Ast.pfile in
  845. let fkey = file ^ "!" ^ get_signature ctx.com in
  846. (* force parsing again : if the completion point have been changed *)
  847. Hashtbl.remove cache.c_files fkey;
  848. (* force module reloading (if cached) *)
  849. Hashtbl.iter (fun _ m -> if m.m_extra.m_file = file then m.m_extra.m_dirty <- true) cache.c_modules
  850. end
  851. );
  852. ctx.com.print <- (fun str -> ssend sin ("\x01" ^ String.concat "\x01" (ExtString.String.nsplit str "\n") ^ "\n"));
  853. ctx
  854. in
  855. (try
  856. let data = parse_hxml_data (read_loop 0) in
  857. Unix.clear_nonblock sin;
  858. if verbose then print_endline ("Processing Arguments [" ^ String.concat "," data ^ "]");
  859. (try
  860. Common.display_default := DMNone;
  861. Parser.resume_display := Ast.null_pos;
  862. Typeload.return_partial_type := false;
  863. measure_times := false;
  864. close_times();
  865. stats.s_files_parsed := 0;
  866. stats.s_classes_built := 0;
  867. stats.s_methods_typed := 0;
  868. stats.s_macros_called := 0;
  869. Hashtbl.clear Common.htimers;
  870. let _ = Common.timer "other" in
  871. incr compilation_step;
  872. compilation_mark := !mark_loop;
  873. start_time := get_time();
  874. process_params create data;
  875. close_times();
  876. if !measure_times then report_times (fun s -> ssend sin (s ^ "\n"))
  877. with Completion str ->
  878. if verbose then print_endline ("Completion Response =\n" ^ str);
  879. ssend sin str
  880. );
  881. if verbose then begin
  882. 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));
  883. print_endline (Printf.sprintf "Time spent : %.3fs" (get_time() -. t0));
  884. end
  885. with Unix.Unix_error _ ->
  886. if verbose then print_endline "Connection Aborted"
  887. | e ->
  888. let estr = Printexc.to_string e in
  889. if verbose then print_endline ("Uncaught Error : " ^ estr);
  890. (try ssend sin estr with _ -> ());
  891. );
  892. Unix.close sin;
  893. (* prevent too much fragmentation by doing some compactions every X run *)
  894. incr run_count;
  895. if !run_count mod 10 = 0 then begin
  896. let t0 = get_time() in
  897. Gc.compact();
  898. if verbose then begin
  899. let stat = Gc.quick_stat() in
  900. let size = (float_of_int stat.Gc.heap_words) *. 4. in
  901. print_endline (Printf.sprintf "Compacted memory %.3fs %.1fMB" (get_time() -. t0) (size /. (1024. *. 1024.)));
  902. end
  903. end else Gc.minor();
  904. done
  905. and do_connect host port args =
  906. let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
  907. (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));
  908. let args = ("--cwd " ^ Unix.getcwd()) :: args in
  909. ssend sock (String.concat "" (List.map (fun a -> a ^ "\n") args) ^ "\000");
  910. let has_error = ref false in
  911. let rec print line =
  912. match (if line = "" then '\x00' else line.[0]) with
  913. | '\x01' ->
  914. print_string (String.concat "\n" (List.tl (ExtString.String.nsplit line "\x01")));
  915. flush stdout
  916. | '\x02' ->
  917. has_error := true;
  918. | _ ->
  919. prerr_endline line;
  920. in
  921. let buf = Buffer.create 0 in
  922. let process() =
  923. let lines = ExtString.String.nsplit (Buffer.contents buf) "\n" in
  924. (* the last line ends with \n *)
  925. let lines = (match List.rev lines with "" :: l -> List.rev l | _ -> lines) in
  926. List.iter print lines;
  927. in
  928. let tmp = String.create 1024 in
  929. let rec loop() =
  930. let b = Unix.recv sock tmp 0 1024 [] in
  931. Buffer.add_substring buf tmp 0 b;
  932. if b > 0 then begin
  933. if String.get tmp (b - 1) = '\n' then begin
  934. process();
  935. Buffer.reset buf;
  936. end;
  937. loop();
  938. end
  939. in
  940. loop();
  941. process();
  942. if !has_error then exit 1
  943. and init ctx =
  944. let usage = Printf.sprintf
  945. "Haxe Compiler %s - (C)2005-2015 Haxe Foundation\n Usage : haxe%s -main <class> [-swf|-js|-neko|-php|-cpp|-as3|-cs|-java|-python] <output> [options]\n Options :"
  946. s_version (if Sys.os_type = "Win32" then ".exe" else "")
  947. in
  948. let com = ctx.com in
  949. let classes = ref [([],"Std")] in
  950. try
  951. let xml_out = ref None in
  952. let swf_header = ref None in
  953. let cmds = ref [] in
  954. let config_macros = ref [] in
  955. let cp_libs = ref [] in
  956. let added_libs = Hashtbl.create 0 in
  957. let no_output = ref false in
  958. let did_something = ref false in
  959. let force_typing = ref false in
  960. let pre_compilation = ref [] in
  961. let interp = ref false in
  962. let swf_version = ref false in
  963. let evals = ref [] in
  964. Common.define_value com Define.HaxeVer (float_repres (float_of_int version /. 1000.));
  965. Common.define_value com Define.HxcppApiLevel "321";
  966. Common.raw_define com "haxe3";
  967. Common.define_value com Define.Dce "std";
  968. com.warning <- (fun msg p -> message ctx ("Warning : " ^ msg) p);
  969. com.error <- error ctx;
  970. if !global_cache <> None then com.run_command <- run_command ctx;
  971. Parser.display_error := (fun e p -> com.error (Parser.error_msg e) p);
  972. Parser.use_doc := !Common.display_default <> DMNone || (!global_cache <> None);
  973. (try
  974. let p = Sys.getenv "HAXE_STD_PATH" in
  975. let rec loop = function
  976. | drive :: path :: l ->
  977. if String.length drive = 1 && ((drive.[0] >= 'a' && drive.[0] <= 'z') || (drive.[0] >= 'A' && drive.[0] <= 'Z')) then
  978. (drive ^ ":" ^ path) :: loop l
  979. else
  980. drive :: loop (path :: l)
  981. | l ->
  982. l
  983. in
  984. let parts = Str.split_delim (Str.regexp "[;:]") p in
  985. com.class_path <- "" :: List.map normalize_path (loop parts)
  986. with
  987. Not_found ->
  988. if Sys.os_type = "Unix" then
  989. com.class_path <- ["/usr/lib/haxe/std/";"/usr/share/haxe/std/";"/usr/local/lib/haxe/std/";"/usr/lib/haxe/extraLibs/";"/usr/local/lib/haxe/extraLibs/";""]
  990. else
  991. let base_path = normalize_path (get_real_path (try executable_path() with _ -> "./")) in
  992. com.class_path <- [base_path ^ "std/";base_path ^ "extraLibs/";""]);
  993. com.std_path <- List.filter (fun p -> ExtString.String.ends_with p "std/" || ExtString.String.ends_with p "std\\") com.class_path;
  994. let set_platform pf file =
  995. if com.platform <> Cross then failwith "Multiple targets";
  996. Common.init_platform com pf;
  997. com.file <- file;
  998. if (pf = Flash) && file_extension file = "swc" then Common.define com Define.Swc;
  999. in
  1000. let define f = Arg.Unit (fun () -> Common.define com f) in
  1001. let process_ref = ref (fun args -> ()) in
  1002. let process_libs() =
  1003. let libs = List.filter (fun l -> not (Hashtbl.mem added_libs l)) (List.rev !cp_libs) in
  1004. cp_libs := [];
  1005. List.iter (fun l -> Hashtbl.add added_libs l ()) libs;
  1006. (* immediately process the arguments to insert them at the place -lib was defined *)
  1007. match add_libs com libs with
  1008. | [] -> ()
  1009. | args -> (!process_ref) args
  1010. in
  1011. let arg_delays = ref [] in
  1012. let basic_args_spec = [
  1013. ("-cp",Arg.String (fun path ->
  1014. process_libs();
  1015. com.class_path <- normalize_path path :: com.class_path
  1016. ),"<path> : add a directory to find source files");
  1017. ("-js",Arg.String (set_platform Js),"<file> : compile code to JavaScript file");
  1018. ("-swf",Arg.String (set_platform Flash),"<file> : compile code to Flash SWF file");
  1019. ("-as3",Arg.String (fun dir ->
  1020. set_platform Flash dir;
  1021. Common.define com Define.As3;
  1022. Common.define com Define.NoInline;
  1023. ),"<directory> : generate AS3 code into target directory");
  1024. ("-neko",Arg.String (set_platform Neko),"<file> : compile code to Neko Binary");
  1025. ("-php",Arg.String (fun dir ->
  1026. classes := (["php"],"Boot") :: !classes;
  1027. set_platform Php dir;
  1028. ),"<directory> : generate PHP code into target directory");
  1029. ("-cpp",Arg.String (fun dir ->
  1030. set_platform Cpp dir;
  1031. ),"<directory> : generate C++ code into target directory");
  1032. ("-cs",Arg.String (fun dir ->
  1033. cp_libs := "hxcs" :: !cp_libs;
  1034. set_platform Cs dir;
  1035. ),"<directory> : generate C# code into target directory");
  1036. ("-java",Arg.String (fun dir ->
  1037. cp_libs := "hxjava" :: !cp_libs;
  1038. set_platform Java dir;
  1039. ),"<directory> : generate Java code into target directory");
  1040. ("-python",Arg.String (fun dir ->
  1041. set_platform Python dir;
  1042. ),"<file> : generate Python code as target file");
  1043. ("-xml",Arg.String (fun file ->
  1044. Parser.use_doc := true;
  1045. xml_out := Some file
  1046. ),"<file> : generate XML types description");
  1047. ("-main",Arg.String (fun cl ->
  1048. if com.main_class <> None then raise (Arg.Bad "Multiple -main");
  1049. let cpath = make_type_path cl in
  1050. com.main_class <- Some cpath;
  1051. classes := cpath :: !classes
  1052. ),"<class> : select startup class");
  1053. ("-lib",Arg.String (fun l ->
  1054. cp_libs := l :: !cp_libs;
  1055. Common.raw_define com l;
  1056. ),"<library[:version]> : use a haxelib library");
  1057. ("-D",Arg.String (fun var ->
  1058. begin match var with
  1059. | "no_copt" | "no-copt" -> com.foptimize <- false;
  1060. | "use_rtti_doc" | "use-rtti-doc" -> Parser.use_doc := true;
  1061. | _ -> if List.mem var reserved_flags then raise (Arg.Bad (var ^ " is a reserved compiler flag and cannot be defined from command line"));
  1062. end;
  1063. Common.raw_define com var;
  1064. ),"<var[=value]> : define a conditional compilation flag");
  1065. ("-v",Arg.Unit (fun () ->
  1066. com.verbose <- true
  1067. ),": turn on verbose mode");
  1068. ("-debug", Arg.Unit (fun() ->
  1069. Common.define com Define.Debug;
  1070. com.debug <- true;
  1071. ), ": add debug information to the compiled code");
  1072. ] in
  1073. let adv_args_spec = [
  1074. ("-dce", Arg.String (fun mode ->
  1075. (match mode with
  1076. | "std" | "full" | "no" -> ()
  1077. | _ -> raise (Arg.Bad "Invalid DCE mode, expected std | full | no"));
  1078. Common.define_value com Define.Dce mode
  1079. ),"[std|full|no] : set the dead code elimination mode (default std)");
  1080. ("-swf-version",Arg.Float (fun v ->
  1081. if not !swf_version || com.flash_version < v then com.flash_version <- v;
  1082. swf_version := true;
  1083. ),"<version> : change the SWF version");
  1084. ("-swf-header",Arg.String (fun h ->
  1085. try
  1086. swf_header := Some (match ExtString.String.nsplit h ":" with
  1087. | [width; height; fps] ->
  1088. (int_of_string width,int_of_string height,float_of_string fps,0xFFFFFF)
  1089. | [width; height; fps; color] ->
  1090. let color = if ExtString.String.starts_with color "0x" then color else "0x" ^ color in
  1091. (int_of_string width, int_of_string height, float_of_string fps, int_of_string color)
  1092. | _ -> raise Exit)
  1093. with
  1094. _ -> raise (Arg.Bad "Invalid SWF header format, expected width:height:fps[:color]")
  1095. ),"<header> : define SWF header (width:height:fps:color)");
  1096. ("-swf-lib",Arg.String (fun file ->
  1097. process_libs(); (* linked swf order matters, and lib might reference swf as well *)
  1098. Genswf.add_swf_lib com file false
  1099. ),"<file> : add the SWF library to the compiled SWF");
  1100. ("-swf-lib-extern",Arg.String (fun file ->
  1101. Genswf.add_swf_lib com file true
  1102. ),"<file> : use the SWF library for type checking");
  1103. ("-java-lib",Arg.String (fun file ->
  1104. let std = file = "lib/hxjava-std.jar" in
  1105. arg_delays := (fun () -> Genjava.add_java_lib com file std) :: !arg_delays;
  1106. ),"<file> : add an external JAR or class directory library");
  1107. ("-net-lib",Arg.String (fun file ->
  1108. let file, is_std = match ExtString.String.nsplit file "@" with
  1109. | [file] ->
  1110. file,false
  1111. | [file;"std"] ->
  1112. file,true
  1113. | _ -> raise Exit
  1114. in
  1115. arg_delays := (fun () -> Gencs.add_net_lib com file is_std) :: !arg_delays;
  1116. ),"<file>[@std] : add an external .NET DLL file");
  1117. ("-net-std",Arg.String (fun file ->
  1118. Gencs.add_net_std com file
  1119. ),"<file> : add a root std .NET DLL search path");
  1120. ("-c-arg",Arg.String (fun arg ->
  1121. com.c_args <- arg :: com.c_args
  1122. ),"<arg> : pass option <arg> to the native Java/C# compiler");
  1123. ("-x", Arg.String (fun file ->
  1124. let neko_file = file ^ ".n" in
  1125. set_platform Neko neko_file;
  1126. if com.main_class = None then begin
  1127. let cpath = make_type_path file in
  1128. com.main_class <- Some cpath;
  1129. classes := cpath :: !classes
  1130. end;
  1131. cmds := ("neko " ^ neko_file) :: !cmds;
  1132. ),"<file> : shortcut for compiling and executing a neko file");
  1133. ("-resource",Arg.String (fun res ->
  1134. let file, name = (match ExtString.String.nsplit res "@" with
  1135. | [file; name] -> file, name
  1136. | [file] -> file, file
  1137. | _ -> raise (Arg.Bad "Invalid Resource format, expected file@name")
  1138. ) in
  1139. let file = (try Common.find_file com file with Not_found -> file) in
  1140. let data = (try
  1141. let s = Std.input_file ~bin:true file in
  1142. if String.length s > 12000000 then raise Exit;
  1143. s;
  1144. with
  1145. | Sys_error _ -> failwith ("Resource file not found : " ^ file)
  1146. | _ -> failwith ("Resource '" ^ file ^ "' excess the maximum size of 12MB")
  1147. ) in
  1148. if Hashtbl.mem com.resources name then failwith ("Duplicate resource name " ^ name);
  1149. Hashtbl.add com.resources name data
  1150. ),"<file>[@name] : add a named resource file");
  1151. ("-prompt", Arg.Unit (fun() -> prompt := true),": prompt on error");
  1152. ("-cmd", Arg.String (fun cmd ->
  1153. cmds := unquote cmd :: !cmds
  1154. ),": run the specified command after successful compilation");
  1155. ("--flash-strict", define Define.FlashStrict, ": more type strict flash API");
  1156. ("--no-traces", define Define.NoTraces, ": don't compile trace calls in the program");
  1157. ("--gen-hx-classes", Arg.Unit (fun() ->
  1158. force_typing := true;
  1159. pre_compilation := (fun() ->
  1160. List.iter (fun (_,_,extract) ->
  1161. Hashtbl.iter (fun n _ -> classes := n :: !classes) (extract())
  1162. ) com.swf_libs;
  1163. List.iter (fun (_,std,_,all_files,_) ->
  1164. if not std then
  1165. List.iter (fun path -> if path <> (["java";"lang"],"String") then classes := path :: !classes) (all_files())
  1166. ) com.java_libs;
  1167. List.iter (fun (_,std,all_files,_) ->
  1168. if not std then
  1169. List.iter (fun path -> classes := path :: !classes) (all_files())
  1170. ) com.net_libs;
  1171. ) :: !pre_compilation;
  1172. xml_out := Some "hx"
  1173. ),": generate hx headers for all input classes");
  1174. ("--next", Arg.Unit (fun() -> assert false), ": separate several haxe compilations");
  1175. ("--each", Arg.Unit (fun() -> assert false), ": append preceding parameters to all haxe compilations separated by --next");
  1176. ("--display", Arg.String (fun file_pos ->
  1177. match file_pos with
  1178. | "classes" ->
  1179. pre_compilation := (fun() -> raise (Parser.TypePath (["."],None,true))) :: !pre_compilation;
  1180. | "keywords" ->
  1181. complete_fields com (Hashtbl.fold (fun k _ acc -> (k,"",None,"") :: acc) Lexer.keywords [])
  1182. | "memory" ->
  1183. did_something := true;
  1184. (try display_memory ctx with e -> prerr_endline (Printexc.get_backtrace ()));
  1185. | _ ->
  1186. let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in
  1187. let file = unquote file in
  1188. let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
  1189. let activate_special_display_mode () =
  1190. Common.define com Define.NoCOpt;
  1191. Parser.use_parser_resume := false
  1192. in
  1193. let mode = match smode with
  1194. | "position" ->
  1195. activate_special_display_mode();
  1196. DMPosition
  1197. | "usage" ->
  1198. activate_special_display_mode();
  1199. DMUsage
  1200. | "type" ->
  1201. activate_special_display_mode();
  1202. DMType
  1203. | "toplevel" ->
  1204. activate_special_display_mode();
  1205. DMToplevel
  1206. | "" ->
  1207. Parser.use_parser_resume := true;
  1208. DMDefault
  1209. | _ ->
  1210. let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in
  1211. match smode with
  1212. | "resolve" ->
  1213. activate_special_display_mode();
  1214. DMResolve arg
  1215. | _ ->
  1216. Parser.use_parser_resume := true;
  1217. DMDefault
  1218. in
  1219. let pos = try int_of_string pos with _ -> failwith ("Invalid format : " ^ pos) in
  1220. com.display <- mode;
  1221. Common.display_default := mode;
  1222. Common.define_value com Define.Display (if smode <> "" then smode else "1");
  1223. Parser.use_doc := true;
  1224. Parser.resume_display := {
  1225. Ast.pfile = Common.unique_full_path file;
  1226. Ast.pmin = pos;
  1227. Ast.pmax = pos;
  1228. };
  1229. ),": display code tips");
  1230. ("--no-output", Arg.Unit (fun() -> no_output := true),": compiles but does not generate any file");
  1231. ("--times", Arg.Unit (fun() -> measure_times := true),": measure compilation times");
  1232. ("--no-inline", define Define.NoInline, ": disable inlining");
  1233. ("--no-opt", Arg.Unit (fun() ->
  1234. com.foptimize <- false;
  1235. Common.define com Define.NoOpt;
  1236. ), ": disable code optimizations");
  1237. ("--php-front",Arg.String (fun f ->
  1238. if com.php_front <> None then raise (Arg.Bad "Multiple --php-front");
  1239. com.php_front <- Some f;
  1240. ),"<filename> : select the name for the php front file");
  1241. ("--php-lib",Arg.String (fun f ->
  1242. if com.php_lib <> None then raise (Arg.Bad "Multiple --php-lib");
  1243. com.php_lib <- Some f;
  1244. ),"<filename> : select the name for the php lib folder");
  1245. ("--php-prefix", Arg.String (fun f ->
  1246. if com.php_prefix <> None then raise (Arg.Bad "Multiple --php-prefix");
  1247. com.php_prefix <- Some f;
  1248. Common.define com Define.PhpPrefix;
  1249. ),"<name> : prefix all classes with given name");
  1250. ("--remap", Arg.String (fun s ->
  1251. let pack, target = (try ExtString.String.split s ":" with _ -> raise (Arg.Bad "Invalid remap format, expected source:target")) in
  1252. com.package_rules <- PMap.add pack (Remap target) com.package_rules;
  1253. ),"<package:target> : remap a package to another one");
  1254. ("--interp", Arg.Unit (fun() ->
  1255. Common.define com Define.Interp;
  1256. set_platform Neko "";
  1257. interp := true;
  1258. ),": interpret the program using internal macro system");
  1259. ("--macro", Arg.String (fun e ->
  1260. force_typing := true;
  1261. config_macros := e :: !config_macros
  1262. )," : call the given macro before typing anything else");
  1263. ("--eval", Arg.String (fun s ->
  1264. force_typing := true;
  1265. evals := s :: !evals;
  1266. ), " : evaluates argument as Haxe module code");
  1267. ("--wait", Arg.String (fun hp ->
  1268. let host, port = (try ExtString.String.split hp ":" with _ -> "127.0.0.1", hp) in
  1269. wait_loop com host (try int_of_string port with _ -> raise (Arg.Bad "Invalid port"))
  1270. ),"<[host:]port> : wait on the given port for commands to run)");
  1271. ("--connect",Arg.String (fun _ ->
  1272. assert false
  1273. ),"<[host:]port> : connect on the given port and run commands there)");
  1274. ("--cwd", Arg.String (fun dir ->
  1275. assert false
  1276. ),"<dir> : set current working directory");
  1277. ("-version",Arg.Unit (fun() ->
  1278. message ctx s_version Ast.null_pos;
  1279. did_something := true;
  1280. ),": print version and exit");
  1281. ("--help-defines", Arg.Unit (fun() ->
  1282. let m = ref 0 in
  1283. let rec loop i =
  1284. let d = Obj.magic i in
  1285. if d <> Define.Last then begin
  1286. let t, doc = Define.infos d in
  1287. if String.length t > !m then m := String.length t;
  1288. ((String.concat "-" (ExtString.String.nsplit t "_")),doc) :: (loop (i + 1))
  1289. end else
  1290. []
  1291. in
  1292. let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
  1293. let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" !m n (limit_string doc (!m + 3))) all in
  1294. List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all;
  1295. did_something := true
  1296. ),": print help for all compiler specific defines");
  1297. ("--help-metas", Arg.Unit (fun() ->
  1298. let m = ref 0 in
  1299. let rec loop i =
  1300. let d = Obj.magic i in
  1301. if d <> Meta.Last then begin
  1302. let t, (doc,flags) = MetaInfo.to_string d in
  1303. if not (List.mem MetaInfo.Internal flags) then begin
  1304. let params = ref [] and used = ref [] and pfs = ref [] in
  1305. List.iter (function
  1306. | MetaInfo.HasParam s -> params := s :: !params
  1307. | MetaInfo.Platform f -> pfs := f :: !pfs
  1308. | MetaInfo.Platforms fl -> pfs := fl @ !pfs
  1309. | MetaInfo.UsedOn u -> used := u :: !used
  1310. | MetaInfo.UsedOnEither ul -> used := ul @ !used
  1311. | MetaInfo.Internal -> assert false
  1312. ) flags;
  1313. let params = (match List.rev !params with
  1314. | [] -> ""
  1315. | l -> "(" ^ String.concat "," l ^ ")"
  1316. ) in
  1317. let pfs = (match List.rev !pfs with
  1318. | [] -> ""
  1319. | [p] -> " (" ^ platform_name p ^ " only)"
  1320. | pl -> " (for " ^ String.concat "," (List.map platform_name pl) ^ ")"
  1321. ) in
  1322. let str = "@" ^ t in
  1323. if String.length str > !m then m := String.length str;
  1324. (str,params ^ doc ^ pfs) :: loop (i + 1)
  1325. end else
  1326. loop (i + 1)
  1327. end else
  1328. []
  1329. in
  1330. let all = List.sort (fun (s1,_) (s2,_) -> String.compare s1 s2) (loop 0) in
  1331. let all = List.map (fun (n,doc) -> Printf.sprintf " %-*s: %s" !m n (limit_string doc (!m + 3))) all in
  1332. List.iter (fun msg -> ctx.com.print (msg ^ "\n")) all;
  1333. did_something := true
  1334. ),": print help for all compiler metadatas");
  1335. ] in
  1336. let args_callback cl =
  1337. let path,name = make_path cl in
  1338. if starts_uppercase name then
  1339. classes := (path,name) :: !classes
  1340. else begin
  1341. force_typing := true;
  1342. config_macros := (Printf.sprintf "include('%s')" cl) :: !config_macros;
  1343. end
  1344. in
  1345. let all_args_spec = basic_args_spec @ adv_args_spec in
  1346. let process args =
  1347. let current = ref 0 in
  1348. (try
  1349. Arg.parse_argv ~current (Array.of_list ("" :: List.map expand_env args)) all_args_spec args_callback usage;
  1350. List.iter (fun fn -> fn()) !arg_delays
  1351. with (Arg.Bad msg) as exc ->
  1352. let r = Str.regexp "unknown option `\\([-A-Za-z]+\\)'" in
  1353. try
  1354. ignore(Str.search_forward r msg 0);
  1355. let s = Str.matched_group 1 msg in
  1356. let sl = List.map (fun (s,_,_) -> s) all_args_spec in
  1357. let msg = Typecore.string_error_raise s sl (Printf.sprintf "Invalid command: %s" s) in
  1358. raise (Arg.Bad msg)
  1359. with Not_found ->
  1360. raise exc);
  1361. arg_delays := []
  1362. in
  1363. process_ref := process;
  1364. process ctx.com.args;
  1365. process_libs();
  1366. if com.display <> DMNone then begin
  1367. com.warning <- message ctx;
  1368. com.error <- error ctx;
  1369. com.main_class <- None;
  1370. let real = get_real_path (!Parser.resume_display).Ast.pfile in
  1371. classes := lookup_classes com real;
  1372. if !classes = [] then begin
  1373. if not (Sys.file_exists real) then failwith "Display file does not exist";
  1374. (match List.rev (ExtString.String.nsplit real path_sep) with
  1375. | file :: _ when file.[0] >= 'a' && file.[1] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
  1376. | _ -> ());
  1377. failwith "Display file was not found in class path";
  1378. end;
  1379. Common.log com ("Display file : " ^ real);
  1380. Common.log com ("Classes found : [" ^ (String.concat "," (List.map Ast.s_type_path !classes)) ^ "]");
  1381. end;
  1382. let add_std dir =
  1383. 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
  1384. in
  1385. let ext = (match com.platform with
  1386. | Cross ->
  1387. (* no platform selected *)
  1388. set_platform Cross "";
  1389. "?"
  1390. | Flash ->
  1391. let rec loop = function
  1392. | [] -> ()
  1393. | (v,_) :: _ when v > com.flash_version -> ()
  1394. | (v,def) :: l ->
  1395. Common.raw_define com ("flash" ^ def);
  1396. loop l
  1397. in
  1398. loop Common.flash_versions;
  1399. Common.raw_define com "flash";
  1400. com.package_rules <- PMap.remove "flash" com.package_rules;
  1401. add_std "flash";
  1402. "swf"
  1403. | Neko ->
  1404. add_std "neko";
  1405. "n"
  1406. | Js ->
  1407. if not (PMap.exists (fst (Define.infos Define.JqueryVer)) com.defines) then
  1408. Common.define_value com Define.JqueryVer "11103";
  1409. add_std "js";
  1410. "js"
  1411. | Php ->
  1412. add_std "php";
  1413. "php"
  1414. | Cpp ->
  1415. add_std "cpp";
  1416. "cpp"
  1417. | Cs ->
  1418. let old_flush = ctx.flush in
  1419. ctx.flush <- (fun () ->
  1420. com.net_libs <- [];
  1421. old_flush()
  1422. );
  1423. Gencs.before_generate com;
  1424. add_std "cs"; "cs"
  1425. | Java ->
  1426. let old_flush = ctx.flush in
  1427. ctx.flush <- (fun () ->
  1428. List.iter (fun (_,_,close,_,_) -> close()) com.java_libs;
  1429. com.java_libs <- [];
  1430. old_flush()
  1431. );
  1432. Genjava.before_generate com;
  1433. add_std "java"; "java"
  1434. | Python ->
  1435. add_std "python";
  1436. "python"
  1437. ) in
  1438. (* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *)
  1439. begin match com.display with
  1440. | DMNone | DMToplevel ->
  1441. ()
  1442. | _ ->
  1443. if 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;
  1444. end;
  1445. com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)
  1446. List.iter (fun f -> f()) (List.rev (!pre_compilation));
  1447. if !classes = [([],"Std")] && not !force_typing then begin
  1448. let help_spec = basic_args_spec @ [
  1449. ("-help", Arg.Unit (fun () -> ()),": show extended help information");
  1450. ("--help", Arg.Unit (fun () -> ()),": show extended help information");
  1451. ("--help-defines", Arg.Unit (fun () -> ()),": print help for all compiler specific defines");
  1452. ("--help-metas", Arg.Unit (fun () -> ()),": print help for all compiler metadatas");
  1453. ("<dot-path>", Arg.Unit (fun () -> ()),": compile the module specified by dot-path");
  1454. ] in
  1455. if !cmds = [] && not !did_something then Arg.usage help_spec usage;
  1456. end else begin
  1457. ctx.setup();
  1458. Common.log com ("Classpath : " ^ (String.concat ";" com.class_path));
  1459. Common.log com ("Defines : " ^ (String.concat ";" (PMap.foldi (fun k v acc -> (match v with "1" -> k | _ -> k ^ "=" ^ v) :: acc) com.defines [])));
  1460. let t = Common.timer "typing" in
  1461. Typecore.type_expr_ref := (fun ctx e with_type -> Typer.type_expr ctx e with_type);
  1462. let tctx = Typer.create com in
  1463. List.iter (Typer.call_init_macro tctx) (List.rev !config_macros);
  1464. List.iter (Typer.eval tctx) !evals;
  1465. List.iter (fun cpath -> ignore(tctx.Typecore.g.Typecore.do_load_module tctx cpath Ast.null_pos)) (List.rev !classes);
  1466. Typer.finalize tctx;
  1467. t();
  1468. if ctx.has_error then raise Abort;
  1469. begin match com.display with
  1470. | DMNone | DMUsage | DMPosition | DMType | DMResolve _ ->
  1471. ()
  1472. | _ ->
  1473. if ctx.has_next then raise Abort;
  1474. failwith "No completion point was found";
  1475. end;
  1476. let t = Common.timer "filters" in
  1477. let main, types, modules = Typer.generate tctx in
  1478. com.main <- main;
  1479. com.types <- types;
  1480. com.modules <- modules;
  1481. Filters.run com tctx main;
  1482. if ctx.has_error then raise Abort;
  1483. (* check file extension. In case of wrong commandline, we don't want
  1484. to accidentaly delete a source file. *)
  1485. if not !no_output && file_extension com.file = ext then delete_file com.file;
  1486. (match !xml_out with
  1487. | None -> ()
  1488. | Some "hx" ->
  1489. Genxml.generate_hx com
  1490. | Some file ->
  1491. Common.log com ("Generating xml : " ^ file);
  1492. Common.mkdir_from_path file;
  1493. Genxml.generate com file);
  1494. if com.platform = Flash || com.platform = Cpp then List.iter (Codegen.fix_overrides com) com.types;
  1495. if Common.defined com Define.Dump then Codegen.dump_types com;
  1496. if Common.defined com Define.DumpDependencies then Codegen.dump_dependencies com;
  1497. t();
  1498. if not !no_output then begin match com.platform with
  1499. | Neko when !interp -> ()
  1500. | Cpp when Common.defined com Define.Cppia -> ()
  1501. | Cpp | Cs | Java | Php -> Common.mkdir_from_path (com.file ^ "/.")
  1502. | _ -> Common.mkdir_from_path com.file
  1503. end;
  1504. if not !no_output then begin
  1505. if !interp then begin
  1506. let ctx = Interp.create com (Typer.make_macro_api tctx Ast.null_pos) in
  1507. Interp.add_types ctx com.types (fun t -> ());
  1508. (match com.main with
  1509. | None -> ()
  1510. | Some e -> ignore(Interp.eval_expr ctx e));
  1511. end else if com.platform = Cross then
  1512. ()
  1513. else begin
  1514. let generate,name = match com.platform with
  1515. | Flash when Common.defined com Define.As3 ->
  1516. Genas3.generate,"AS3"
  1517. | Flash ->
  1518. Genswf.generate !swf_header,"swf"
  1519. | Neko ->
  1520. Genneko.generate,"neko"
  1521. | Js ->
  1522. Genjs.generate,"js"
  1523. | Php ->
  1524. Genphp.generate,"php"
  1525. | Cpp ->
  1526. Gencpp.generate,"cpp"
  1527. | Cs ->
  1528. Gencs.generate,"cs"
  1529. | Java ->
  1530. Genjava.generate,"java"
  1531. | Python ->
  1532. Genpy.generate,"python"
  1533. | Cross ->
  1534. assert false
  1535. in
  1536. Common.log com ("Generating " ^ name ^ ": " ^ com.file);
  1537. let t = Common.timer ("generate " ^ name) in
  1538. generate com;
  1539. t()
  1540. end
  1541. end
  1542. end;
  1543. Sys.catch_break false;
  1544. List.iter (fun f -> f()) (List.rev com.final_filters);
  1545. if not !no_output then begin
  1546. List.iter (fun c ->
  1547. let r = run_command ctx c in
  1548. if r <> 0 then failwith ("Command failed with error " ^ string_of_int r)
  1549. ) (List.rev !cmds)
  1550. end
  1551. with
  1552. | Abort ->
  1553. ()
  1554. | Ast.Error (m,p) ->
  1555. error ctx m p
  1556. | Typecore.Fatal_error (m,p) ->
  1557. error ctx m p
  1558. | Common.Abort (m,p) ->
  1559. error ctx m p
  1560. | Lexer.Error (m,p) ->
  1561. error ctx (Lexer.error_msg m) p
  1562. | Parser.Error (m,p) ->
  1563. error ctx (Parser.error_msg m) p
  1564. | Typecore.Forbid_package ((pack,m,p),pl,pf) ->
  1565. if !Common.display_default <> DMNone && ctx.has_next then begin
  1566. ctx.has_error <- false;
  1567. ctx.messages <- [];
  1568. end else begin
  1569. 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;
  1570. List.iter (error ctx " referenced here") (List.rev pl);
  1571. end
  1572. | Typecore.Error (m,p) ->
  1573. error ctx (Typecore.error_msg m) p
  1574. | Interp.Error (msg,p :: l) ->
  1575. message ctx msg p;
  1576. List.iter (message ctx "Called from") l;
  1577. error ctx "Aborted" Ast.null_pos;
  1578. | Codegen.Generic_Exception(m,p) ->
  1579. error ctx m p
  1580. | Arg.Bad msg ->
  1581. error ctx ("Error: " ^ msg) Ast.null_pos
  1582. | Failure msg when not (is_debug_run()) ->
  1583. error ctx ("Error: " ^ msg) Ast.null_pos
  1584. | Arg.Help msg ->
  1585. message ctx msg Ast.null_pos
  1586. | Typer.DisplayFields fields ->
  1587. let ctx = print_context() in
  1588. let fields = List.map (fun (name,t,kind,doc) -> name, s_type ctx t, kind, (match doc with None -> "" | Some d -> d)) fields in
  1589. let fields = if !measure_times then begin
  1590. close_times();
  1591. let tot = ref 0. in
  1592. Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
  1593. let fields = ("@TOTAL", Printf.sprintf "%.3fs" (get_time() -. !start_time), None, "") :: fields in
  1594. if !tot > 0. then
  1595. Hashtbl.fold (fun _ t acc ->
  1596. ("@TIME " ^ t.name, Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot), None, "") :: acc
  1597. ) Common.htimers fields
  1598. else fields
  1599. end else
  1600. fields
  1601. in
  1602. complete_fields com fields
  1603. | Typecore.DisplayTypes tl ->
  1604. let ctx = print_context() in
  1605. let b = Buffer.create 0 in
  1606. List.iter (fun t ->
  1607. Buffer.add_string b "<type>\n";
  1608. Buffer.add_string b (htmlescape (s_type ctx t));
  1609. Buffer.add_string b "\n</type>\n";
  1610. ) tl;
  1611. raise (Completion (Buffer.contents b))
  1612. | Typecore.DisplayPosition pl ->
  1613. let b = Buffer.create 0 in
  1614. let error_printer file line = sprintf "%s:%d:" (Common.unique_full_path file) line in
  1615. Buffer.add_string b "<list>\n";
  1616. List.iter (fun p ->
  1617. let epos = Lexer.get_error_pos error_printer p in
  1618. Buffer.add_string b "<pos>";
  1619. Buffer.add_string b epos;
  1620. Buffer.add_string b "</pos>\n";
  1621. ) pl;
  1622. Buffer.add_string b "</list>";
  1623. raise (Completion (Buffer.contents b))
  1624. | Typer.DisplayToplevel il ->
  1625. let b = Buffer.create 0 in
  1626. Buffer.add_string b "<il>\n";
  1627. let ctx = print_context() in
  1628. let s_type t = htmlescape (s_type ctx t) in
  1629. List.iter (fun id -> match id with
  1630. | Typer.ITLocal v -> Buffer.add_string b (Printf.sprintf "<i k=\"local\" t=\"%s\">%s</i>\n" (s_type v.v_type) v.v_name);
  1631. | Typer.ITMember(c,cf) -> Buffer.add_string b (Printf.sprintf "<i k=\"member\" t=\"%s\">%s</i>\n" (s_type cf.cf_type) cf.cf_name);
  1632. | Typer.ITStatic(c,cf) -> Buffer.add_string b (Printf.sprintf "<i k=\"static\" t=\"%s\">%s</i>\n" (s_type cf.cf_type) cf.cf_name);
  1633. | Typer.ITEnum(en,ef) -> Buffer.add_string b (Printf.sprintf "<i k=\"enum\" t=\"%s\">%s</i>\n" (s_type ef.ef_type) ef.ef_name);
  1634. | Typer.ITGlobal(mt,s,t) -> Buffer.add_string b (Printf.sprintf "<i k=\"global\" p=\"%s\" t=\"%s\">%s</i>\n" (s_type_path (t_infos mt).mt_path) (s_type t) s);
  1635. | Typer.ITType(mt) -> Buffer.add_string b (Printf.sprintf "<i k=\"type\" p=\"%s\">%s</i>\n" (s_type_path (t_infos mt).mt_path) (snd (t_infos mt).mt_path));
  1636. | Typer.ITPackage s -> Buffer.add_string b (Printf.sprintf "<i k=\"package\">%s</i>\n" s)
  1637. ) il;
  1638. Buffer.add_string b "</il>";
  1639. raise (Completion (Buffer.contents b))
  1640. | Parser.TypePath (p,c,is_import) ->
  1641. (match c with
  1642. | None ->
  1643. let packs, classes = read_type_path com p in
  1644. if packs = [] && classes = [] then
  1645. error ctx ("No classes found in " ^ String.concat "." p) Ast.null_pos
  1646. else
  1647. complete_fields com (
  1648. let convert k f = (f,"",Some k,"") in
  1649. (List.map (convert Typer.FKPackage) packs) @ (List.map (convert Typer.FKType) classes)
  1650. )
  1651. | Some (c,cur_package) ->
  1652. try
  1653. let sl_pack,s_module = match List.rev p with
  1654. | s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s
  1655. | _ -> p,c
  1656. in
  1657. let ctx = Typer.create com in
  1658. let rec lookup p =
  1659. try
  1660. Typeload.load_module ctx (p,s_module) Ast.null_pos
  1661. with e ->
  1662. if cur_package then
  1663. match List.rev p with
  1664. | [] -> raise e
  1665. | _ :: p -> lookup (List.rev p)
  1666. else
  1667. raise e
  1668. in
  1669. let m = lookup sl_pack in
  1670. let statics = ref None in
  1671. let public_types = List.filter (fun t ->
  1672. let tinfos = t_infos t in
  1673. let is_module_type = snd tinfos.mt_path = c in
  1674. if is_import && is_module_type then begin match t with
  1675. | TClassDecl c ->
  1676. ignore(c.cl_build());
  1677. statics := Some c.cl_ordered_statics
  1678. | _ -> ()
  1679. end;
  1680. not tinfos.mt_private
  1681. ) m.m_types in
  1682. let types = if c <> s_module then [] else List.map (fun t -> snd (t_path t),"",Some Typer.FKType,"") public_types in
  1683. let ctx = print_context() in
  1684. let make_field_doc cf =
  1685. cf.cf_name,
  1686. s_type ctx cf.cf_type,
  1687. Some (match cf.cf_kind with Method _ -> Typer.FKMethod | Var _ -> Typer.FKVar),
  1688. (match cf.cf_doc with Some s -> s | None -> "")
  1689. in
  1690. let types = match !statics with
  1691. | None -> types
  1692. | Some cfl -> types @ (List.map make_field_doc (List.filter (fun cf -> cf.cf_public) cfl))
  1693. in
  1694. complete_fields com types
  1695. with Completion c ->
  1696. raise (Completion c)
  1697. | _ ->
  1698. error ctx ("Could not load module " ^ (Ast.s_type_path (p,c))) Ast.null_pos)
  1699. | Interp.Sys_exit i ->
  1700. ctx.flush();
  1701. exit i
  1702. | e when (try Sys.getenv "OCAMLRUNPARAM" <> "b" || !global_cache <> None with _ -> true) && not (is_debug_run()) ->
  1703. error ctx (Printexc.to_string e) Ast.null_pos
  1704. ;;
  1705. let other = Common.timer "other" in
  1706. Sys.catch_break true;
  1707. let args = List.tl (Array.to_list Sys.argv) in
  1708. (try
  1709. let server = Sys.getenv "HAXE_COMPILATION_SERVER" in
  1710. let host, port = (try ExtString.String.split server ":" with _ -> "127.0.0.1", server) in
  1711. do_connect host (try int_of_string port with _ -> failwith "Invalid HAXE_COMPILATION_SERVER port") args
  1712. with Not_found -> try
  1713. process_params create_context args
  1714. with Completion c ->
  1715. prerr_endline c;
  1716. exit 0
  1717. );
  1718. other();
  1719. if !measure_times then report_times prerr_endline