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