main.ml 64 KB

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