Browse Source

move some more display-related things around

Simon Krajewski 9 years ago
parent
commit
1deac88943
7 changed files with 1046 additions and 1010 deletions
  1. 5 3
      Makefile
  2. 191 614
      src/display/display.ml
  3. 784 0
      src/display/displayOutput.ml
  4. 21 342
      src/main.ml
  5. 1 6
      src/server.ml
  6. 29 28
      src/typing/typeload.ml
  7. 15 17
      src/typing/typer.ml

+ 5 - 3
Makefile

@@ -60,7 +60,7 @@ MODULES=json version globals path syntax/ast display/displayTypes typing/type sy
 	generators/genlua \
 	optimization/dce optimization/analyzerConfig optimization/analyzerTypes optimization/analyzerTexpr \
 	optimization/analyzerTexprTransformer optimization/analyzer \
-	optimization/filters typing/typer typing/matcher server main
+	optimization/filters typing/typer typing/matcher display/displayOutput server main
 
 ADD_REVISION?=0
 
@@ -138,6 +138,8 @@ src/display/display.$(MODULE_EXT): src/path.$(MODULE_EXT) src/syntax/ast.$(MODUL
 
 src/display/displayTypes.$(MODULE_EXT) : src/syntax/ast.$(MODULE_EXT)
 
+src/display/displayOutput.$(MODULE_EXT): src/syntax/ast.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/display/display.$(MODULE_EXT)
+
 # generators
 
 src/generators/codegen.$(MODULE_EXT): src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/display/display.$(MODULE_EXT)
@@ -217,13 +219,13 @@ src/typing/typer.$(MODULE_EXT): src/path.$(MODULE_EXT) src/typing/typeload.$(MOD
 
 # main
 
-src/main.$(MODULE_EXT): src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/typing/matcher.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genphp.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/generators/gencpp.$(MODULE_EXT) src/generators/genas3.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/generators/genpy.$(MODULE_EXT) src/generators/genhl.$(MODULE_EXT) src/display/display.$(MODULE_EXT) src/server.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
+src/main.$(MODULE_EXT): src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/typing/matcher.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/generators/genxml.$(MODULE_EXT) src/generators/genswf.$(MODULE_EXT) src/generators/genphp.$(MODULE_EXT) src/generators/genneko.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/generators/gencpp.$(MODULE_EXT) src/generators/genas3.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/generators/genjava.$(MODULE_EXT) src/generators/gencs.$(MODULE_EXT) src/generators/genpy.$(MODULE_EXT) src/generators/genhl.$(MODULE_EXT) src/display/display.$(MODULE_EXT) src/server.$(MODULE_EXT) src/display/displayOutput.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
 src/globals.$(MODULE_EXT): src/version.$(MODULE_EXT)
 
 src/path.$(MODULE_EXT): src/globals.$(MODULE_EXT)
 
-src/server.$(MODULE_EXT): src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
+src/server.$(MODULE_EXT): src/globals.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/display/displayOutput.$(MODULE_EXT)
 
 src/version.$(MODULE_EXT):
 	$(MAKE) -f Makefile.version_extra -s --no-print-directory ADD_REVISION=$(ADD_REVISION) BRANCH=$(BRANCH) COMMIT_SHA=$(COMMIT_SHA) COMMIT_DATE=$(COMMIT_DATE) > src/version.ml

+ 191 - 614
src/display/display.ml

@@ -26,13 +26,12 @@ exception Diagnostics of string
 exception Statistics of string
 exception ModuleSymbols of string
 exception Metadata of string
-exception DisplaySignatures of (t * documentation) list
+exception DisplaySignatures of (t * documentation) list * int
 exception DisplayType of t * pos * string option
 exception DisplayPosition of Ast.pos list
 exception DisplayFields of (string * display_field_kind * documentation) list
 exception DisplayToplevel of IdentifierType.t list
 exception DisplayPackage of string list
-exception DisplaySignature of string
 
 let is_display_file file =
 	file <> "?" && Path.unique_full_path file = (!Parser.resume_display).pfile
@@ -43,277 +42,152 @@ let encloses_position p_target p =
 let is_display_position p =
 	encloses_position !Parser.resume_display p
 
-let find_enclosing com e =
-	let display_pos = ref (!Parser.resume_display) in
-	let mk_null p = (EDisplay(((EConst(Ident "null")),p),false),p) in
-	let encloses_display_pos p =
-		if encloses_position !display_pos p then begin
-			let p = !display_pos in
-			display_pos := { pfile = ""; pmin = -2; pmax = -2 };
-			Some p
-		end else
-			None
-	in
-	let rec loop e = match fst e with
-		| EBlock el ->
-			let p = pos e in
-			(* We want to find the innermost block which contains the display position. *)
-			let el = List.map loop el in
-			let el = match encloses_display_pos p with
-				| None ->
-					el
-				| Some p2 ->
-					let b,el = List.fold_left (fun (b,el) e ->
-						let p = pos e in
-						if b || p.pmax <= p2.pmin then begin
-							(b,e :: el)
-						end else begin
-							let e_d = (EDisplay(mk_null p,false)),p in
-							(true,e :: e_d :: el)
-						end
-					) (false,[]) el in
-					let el = if b then
+module ExprPreprocessing = struct
+	let find_enclosing com e =
+		let display_pos = ref (!Parser.resume_display) in
+		let mk_null p = (EDisplay(((EConst(Ident "null")),p),false),p) in
+		let encloses_display_pos p =
+			if encloses_position !display_pos p then begin
+				let p = !display_pos in
+				display_pos := { pfile = ""; pmin = -2; pmax = -2 };
+				Some p
+			end else
+				None
+		in
+		let rec loop e = match fst e with
+			| EBlock el ->
+				let p = pos e in
+				(* We want to find the innermost block which contains the display position. *)
+				let el = List.map loop el in
+				let el = match encloses_display_pos p with
+					| None ->
 						el
-					else begin
-						mk_null p :: el
-					end in
-					List.rev el
-			in
-			(EBlock el),(pos e)
-		| _ ->
-			Ast.map_expr loop e
-	in
-	loop e
-
-let find_before_pos com e =
-	let display_pos = ref (!Parser.resume_display) in
-	let is_annotated p =
-		if p.pmin <= !display_pos.pmin && p.pmax >= !display_pos.pmax then begin
-			display_pos := { pfile = ""; pmin = -2; pmax = -2 };
-			true
-		end else
-			false
-	in
-	let loop e =
-		if is_annotated (pos e) then
-			(EDisplay(e,false),(pos e))
-		else
-			e
-	in
-	let rec map e =
-		loop (Ast.map_expr map e)
-	in
-	map e
-
-let find_display_call e =
-	let found = ref false in
-	let loop e = if !found then e else match fst e with
-		| ECall _ | ENew _ when is_display_position (pos e) ->
-			found := true;
-			(EDisplay(e,true),(pos e))
-		| _ ->
-			e
-	in
-	let rec map e = match fst e with
-		| EDisplay(_,true) ->
-			found := true;
-			e
-		| EDisplay(e1,false) -> map e1
-		| _ -> loop (Ast.map_expr map e)
-	in
-	map e
-
-let display_module_type dm mt p = match dm.dms_kind with
-	| DMPosition -> raise (DisplayPosition [(t_infos mt).mt_pos]);
-	| DMUsage _ ->
-		let ti = t_infos mt in
-		ti.mt_meta <- (Meta.Usage,[],ti.mt_pos) :: ti.mt_meta
-	| DMType -> raise (DisplayType (type_of_module_type mt,p,None))
-	| _ -> ()
-
-let rec display_type dm t p = match dm.dms_kind with
-	| DMType -> raise (DisplayType (t,p,None))
-	| _ ->
-		try display_module_type dm (module_type_of_type t) p
-		with Exit -> match follow t,follow !t_dynamic_def with
-			| _,TDynamic _ -> () (* sanity check in case it's still t_dynamic *)
-			| TDynamic _,_ -> display_type dm !t_dynamic_def p
-			| _ -> ()
-
-let check_display_type ctx t p =
-	let add_type_hint () =
-		Hashtbl.replace ctx.com.shared.shared_display_information.type_hints p t;
-	in
-	let maybe_display_type () =
-		if ctx.is_display_file && is_display_position p then
-			display_type ctx.com.display t p
-	in
-	match ctx.com.display.dms_kind with
-	| DMStatistics -> add_type_hint()
-	| DMUsage _ -> add_type_hint(); maybe_display_type()
-	| _ -> maybe_display_type()
-
-let display_variable dm v p = match dm.dms_kind with
-	| DMPosition -> raise (DisplayPosition [v.v_pos])
-	| DMUsage _ -> v.v_meta <- (Meta.Usage,[],v.v_pos) :: v.v_meta;
-	| DMType -> raise (DisplayType (v.v_type,p,None))
-	| _ -> ()
-
-let display_field dm cf p = match dm.dms_kind with
-	| DMPosition -> raise (DisplayPosition [cf.cf_pos]);
-	| DMUsage _ -> cf.cf_meta <- (Meta.Usage,[],cf.cf_pos) :: cf.cf_meta;
-	| DMType -> raise (DisplayType (cf.cf_type,p,cf.cf_doc))
-	| _ -> ()
-
-let display_enum_field dm ef p = match dm.dms_kind with
-	| DMPosition -> raise (DisplayPosition [p]);
-	| DMUsage _ -> ef.ef_meta <- (Meta.Usage,[],p) :: ef.ef_meta;
-	| DMType -> raise (DisplayType (ef.ef_type,p,ef.ef_doc))
-	| _ -> ()
-
-let get_timer_fields start_time =
-	let tot = ref 0. in
-	Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
-	let fields = [("@TOTAL", FKTimer (Printf.sprintf "%.3fs" (get_time() -. start_time)), "")] in
-	if !tot > 0. then
-		Hashtbl.fold (fun _ t acc ->
-			("@TIME " ^ t.name, FKTimer (Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot)), "") :: acc
-		) Common.htimers fields
-	else
-		fields
-
-open Json
-
-let htmlescape s =
-	let s = String.concat "&amp;" (ExtString.String.nsplit s "&") in
-	let s = String.concat "&lt;" (ExtString.String.nsplit s "<") in
-	let s = String.concat "&gt;" (ExtString.String.nsplit s ">") in
-	let s = String.concat "&quot;" (ExtString.String.nsplit s "\"") in
-	s
-
-let print_keywords () =
-	let b = Buffer.create 0 in
-	Buffer.add_string b "<list>\n";
-	Hashtbl.iter (fun k _ ->
-		Buffer.add_string b (Printf.sprintf "<i n=\"%s\"></i>\n" k)
-	) Lexer.keywords;
-	Buffer.add_string b "</list>\n";
-	Buffer.contents b
-
-let print_fields fields =
-	let b = Buffer.create 0 in
-	Buffer.add_string b "<list>\n";
-	List.iter (fun (n,k,d) ->
-		let s_kind, t = match k with
-			| FKVar t -> "var", s_type (print_context()) t
-			| FKMethod t -> "method", s_type (print_context()) t
-			| FKType t -> "type", s_type (print_context()) t
-			| FKPackage -> "package", ""
-			| FKModule -> "type", ""
-			| FKMetadata -> "metadata", ""
-			| FKTimer s -> "", s
+					| Some p2 ->
+						let b,el = List.fold_left (fun (b,el) e ->
+							let p = pos e in
+							if b || p.pmax <= p2.pmin then begin
+								(b,e :: el)
+							end else begin
+								let e_d = (EDisplay(mk_null p,false)),p in
+								(true,e :: e_d :: el)
+							end
+						) (false,[]) el in
+						let el = if b then
+							el
+						else begin
+							mk_null p :: el
+						end in
+						List.rev el
+				in
+				(EBlock el),(pos e)
+			| _ ->
+				Ast.map_expr loop e
 		in
-		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))
-	) (List.sort (fun (a,ak,_) (b,bk,_) -> compare (display_field_kind_index ak,a) (display_field_kind_index bk,b)) fields);
-	Buffer.add_string b "</list>\n";
-	Buffer.contents b
-
-let maybe_print_doc d =
-	Option.map_default (fun s -> Printf.sprintf " d=\"%s\"" (htmlescape s)) "" d
-
-let print_toplevel il =
-	let b = Buffer.create 0 in
-	Buffer.add_string b "<il>\n";
-	let s_type t = htmlescape (s_type (print_context()) t) in
-	let s_doc d = maybe_print_doc d in
-	List.iter (fun id -> match id with
-		| IdentifierType.ITLocal v ->
-			Buffer.add_string b (Printf.sprintf "<i k=\"local\" t=\"%s\">%s</i>\n" (s_type v.v_type) v.v_name);
-		| IdentifierType.ITMember(c,cf) ->
-			Buffer.add_string b (Printf.sprintf "<i k=\"member\" t=\"%s\"%s>%s</i>\n" (s_type cf.cf_type) (s_doc cf.cf_doc) cf.cf_name);
-		| IdentifierType.ITStatic(c,cf) ->
-			Buffer.add_string b (Printf.sprintf "<i k=\"static\" t=\"%s\"%s>%s</i>\n" (s_type cf.cf_type) (s_doc cf.cf_doc) cf.cf_name);
-		| IdentifierType.ITEnum(en,ef) ->
-			Buffer.add_string b (Printf.sprintf "<i k=\"enum\" t=\"%s\"%s>%s</i>\n" (s_type ef.ef_type) (s_doc ef.ef_doc) ef.ef_name);
-		| IdentifierType.ITEnumAbstract(a,cf) ->
-			Buffer.add_string b (Printf.sprintf "<i k=\"enumabstract\" t=\"%s\"%s>%s</i>\n" (s_type cf.cf_type) (s_doc cf.cf_doc) cf.cf_name);
-		| IdentifierType.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);
-		| IdentifierType.ITType(mt) ->
-			let infos = t_infos mt in
-			Buffer.add_string b (Printf.sprintf "<i k=\"type\" p=\"%s\"%s>%s</i>\n" (s_type_path infos.mt_path) (s_doc infos.mt_doc) (snd infos.mt_path));
-		| IdentifierType.ITPackage s ->
-			Buffer.add_string b (Printf.sprintf "<i k=\"package\">%s</i>\n" s)
-	) il;
-	Buffer.add_string b "</il>";
-	Buffer.contents b
+		loop e
+
+	let find_before_pos com e =
+		let display_pos = ref (!Parser.resume_display) in
+		let is_annotated p =
+			if p.pmin <= !display_pos.pmin && p.pmax >= !display_pos.pmax then begin
+				display_pos := { pfile = ""; pmin = -2; pmax = -2 };
+				true
+			end else
+				false
+		in
+		let loop e =
+			if is_annotated (pos e) then
+				(EDisplay(e,false),(pos e))
+			else
+				e
+		in
+		let rec map e =
+			loop (Ast.map_expr map e)
+		in
+		map e
+
+	let find_display_call e =
+		let found = ref false in
+		let loop e = if !found then e else match fst e with
+			| ECall _ | ENew _ when is_display_position (pos e) ->
+				found := true;
+				(EDisplay(e,true),(pos e))
+			| _ ->
+				e
+		in
+		let rec map e = match fst e with
+			| EDisplay(_,true) ->
+				found := true;
+				e
+			| EDisplay(e1,false) -> map e1
+			| _ -> loop (Ast.map_expr map e)
+		in
+		map e
 
-let print_type t p doc =
-	let b = Buffer.create 0 in
-	if p = null_pos then
-		Buffer.add_string b "<type"
-	else begin
-		let error_printer file line = Printf.sprintf "%s:%d:" (Path.unique_full_path file) line in
-		let epos = Lexer.get_error_pos error_printer p in
-		Buffer.add_string b ("<type p=\"" ^ (htmlescape epos) ^ "\"")
-	end;
-	Buffer.add_string b (maybe_print_doc doc);
-	Buffer.add_string b ">\n";
-	Buffer.add_string b (htmlescape (s_type (print_context()) t));
-	Buffer.add_string b "\n</type>\n";
-	Buffer.contents b
 
-let print_signatures tl =
-	let b = Buffer.create 0 in
-	List.iter (fun (t,doc) ->
-		Buffer.add_string b "<type";
-		Option.may (fun s -> Buffer.add_string b (Printf.sprintf " d=\"%s\"" (htmlescape s))) doc;
-		Buffer.add_string b ">\n";
-		Buffer.add_string b (htmlescape (s_type (print_context()) (follow t)));
-		Buffer.add_string b "\n</type>\n";
-	) tl;
-	Buffer.contents b
+	let process_expr com e = match com.display.dms_kind with
+		| DMToplevel -> find_enclosing com e
+		| DMPosition | DMUsage _ | DMType -> find_before_pos com e
+		| DMSignature -> find_display_call e
+		| _ -> e
+end
 
-let print_positions pl =
-	let b = Buffer.create 0 in
-	let error_printer file line = Printf.sprintf "%s:%d:" (Path.get_real_path file) line in
-	Buffer.add_string b "<list>\n";
-	List.iter (fun p ->
-		let epos = Lexer.get_error_pos error_printer p in
-		Buffer.add_string b "<pos>";
-		Buffer.add_string b epos;
-		Buffer.add_string b "</pos>\n";
-	) pl;
-	Buffer.add_string b "</list>";
-	Buffer.contents b
+module DisplayEmitter = struct
+	let display_module_type dm mt p = match dm.dms_kind with
+		| DMPosition -> raise (DisplayPosition [(t_infos mt).mt_pos]);
+		| DMUsage _ ->
+			let ti = t_infos mt in
+			ti.mt_meta <- (Meta.Usage,[],ti.mt_pos) :: ti.mt_meta
+		| DMType -> raise (DisplayType (type_of_module_type mt,p,None))
+		| _ -> ()
+
+	let rec display_type dm t p = match dm.dms_kind with
+		| DMType -> raise (DisplayType (t,p,None))
+		| _ ->
+			try display_module_type dm (module_type_of_type t) p
+			with Exit -> match follow t,follow !t_dynamic_def with
+				| _,TDynamic _ -> () (* sanity check in case it's still t_dynamic *)
+				| TDynamic _,_ -> display_type dm !t_dynamic_def p
+				| _ -> ()
 
-(** return a range JSON structure for given position
-    positions are 0-based and the result object looks like this:
-    {
-        start: {line: 0, character: 0},
-        end: {line: 3, character: 42},
-    }
-*)
-let pos_to_json_range p =
-	if p.pmin = -1 then
-		JNull
-	else
-		let l1, p1, l2, p2 = Lexer.get_pos_coords p in
-		let to_json l c = JObject [("line", JInt (l - 1)); ("character", JInt c)] in
-		JObject [
-			("start", to_json l1 p1);
-			("end", to_json l2 p2);
-		]
+	let check_display_type ctx t p =
+		let add_type_hint () =
+			Hashtbl.replace ctx.com.shared.shared_display_information.type_hints p t;
+		in
+		let maybe_display_type () =
+			if ctx.is_display_file && is_display_position p then
+				display_type ctx.com.display t p
+		in
+		match ctx.com.display.dms_kind with
+		| DMStatistics -> add_type_hint()
+		| DMUsage _ -> add_type_hint(); maybe_display_type()
+		| _ -> maybe_display_type()
+
+	let display_variable dm v p = match dm.dms_kind with
+		| DMPosition -> raise (DisplayPosition [v.v_pos])
+		| DMUsage _ -> v.v_meta <- (Meta.Usage,[],v.v_pos) :: v.v_meta;
+		| DMType -> raise (DisplayType (v.v_type,p,None))
+		| _ -> ()
+
+	let display_field dm cf p = match dm.dms_kind with
+		| DMPosition -> raise (DisplayPosition [cf.cf_pos]);
+		| DMUsage _ -> cf.cf_meta <- (Meta.Usage,[],cf.cf_pos) :: cf.cf_meta;
+		| DMType -> raise (DisplayType (cf.cf_type,p,cf.cf_doc))
+		| _ -> ()
+
+	let display_enum_field dm ef p = match dm.dms_kind with
+		| DMPosition -> raise (DisplayPosition [p]);
+		| DMUsage _ -> ef.ef_meta <- (Meta.Usage,[],p) :: ef.ef_meta;
+		| DMType -> raise (DisplayType (ef.ef_type,p,ef.ef_doc))
+		| _ -> ()
+end
 
 module DocumentSymbols = struct
 	open DisplayTypes.SymbolKind
-	open DisplayTypes.SymbolInformation
-	open Json
 
 	let collect_module_symbols (pack,decls) =
 		let l = DynArray.create() in
 		let add name kind location parent =
-			let si = make name kind location (if parent = "" then None else Some parent) in
+			let si = DisplayTypes.SymbolInformation.make name kind location (if parent = "" then None else Some parent) in
 			DynArray.add l si;
 		in
 		let rec expr parent (e,p) =
@@ -384,104 +258,8 @@ module DocumentSymbols = struct
 				List.iter (field (fst d.d_name)) d.d_data
 		) decls;
 		l
-
-	let print_module_symbols com symbols filter =
-		let regex = Option.map Str.regexp_case_fold filter in
-		let reported = Hashtbl.create 0 in
-		let add si =
-			if Hashtbl.mem reported si.pos then false
-			else begin
-				let b = match regex with
-					| None -> true
-					| Some regex -> (try ignore(Str.search_forward regex si.name 0); true with Not_found -> false)
-				in
-				Hashtbl.replace reported si.pos true;
-				b
-			end
-		in
-		let ja = List.fold_left (fun acc (file,l) ->
-			let jl = ExtList.List.filter_map (fun si ->
-				if not (add si) then
-					None
-				else begin
-					let l =
-						("name",JString si.name) ::
-						("kind",JInt (to_int si.kind)) ::
-						("range", pos_to_json_range si.pos) ::
-						(match si.container_name with None -> [] | Some s -> ["containerName",JString s])
-					in
-					Some (JObject l)
-				end
-			) (DynArray.to_list l) in
-			if jl = [] then
-				acc
-			else
-				(JObject [
-					"file",JString file;
-					"symbols",JArray jl
-				]) :: acc
-		) [] symbols in
-		let js = JArray ja in
-		let b = Buffer.create 0 in
-		write_json (Buffer.add_string b) js;
-		Buffer.contents b
 end
 
-type import_display_kind =
-	| IDKPackage of string list
-	| IDKModule of string list * string
-	| IDKSubType of string list * string * string
-	| IDKModuleField of string list * string * string
-	| IDKSubTypeField of string list * string * string * string
-	| IDK
-
-type import_display = import_display_kind * pos
-
-let convert_import_to_something_usable pt path =
-	let rec loop pack m t = function
-		| (s,p) :: l ->
-			let is_lower = is_lower_ident s in
-			let is_display_pos = encloses_position pt p in
-			begin match is_lower,m,t with
-				| _,None,Some _ ->
-					assert false (* impossible, I think *)
-				| true,Some m,None ->
-					if is_display_pos then (IDKModuleField(List.rev pack,m,s),p)
-					else (IDK,p) (* assume that we're done *)
-				| _,Some m,Some t ->
-					if is_display_pos then (IDKSubTypeField(List.rev pack,m,t,s),p)
-					else (IDK,p)
-				| true,None,None ->
-					if is_display_pos then (IDKPackage (List.rev (s :: pack)),p)
-					else loop (s :: pack) m t l
-				| false,Some sm,None ->
-					if is_display_pos then (IDKSubType (List.rev pack,sm,s),p)
-					else loop pack m (Some s) l
-				| false,None,None ->
-					if is_display_pos then (IDKModule (List.rev pack,s),p)
-					else loop pack (Some s) None l
-			end
-		| [] ->
-			(IDK,null_pos)
-	in
-	loop [] None None path
-
-let process_expr com e = match com.display.dms_kind with
-	| DMToplevel -> find_enclosing com e
-	| DMPosition | DMUsage _ | DMType -> find_before_pos com e
-	| DMSignature -> find_display_call e
-	| _ -> e
-
-let add_import_position com p path =
-	com.shared.shared_display_information.import_positions <- PMap.add p (ref false,path) com.shared.shared_display_information.import_positions
-
-let mark_import_position com p =
-	try
-		let r = fst (PMap.find p com.shared.shared_display_information.import_positions) in
-		r := true
-	with Not_found ->
-		()
-
 module Diagnostics = struct
 	module DiagnosticsKind = struct
 		type t =
@@ -495,19 +273,6 @@ module Diagnostics = struct
 			| DKCompilerError -> 2
 	end
 
-	type t = DiagnosticsKind.t * pos
-
-	module UnresolvedIdentifierSuggestion = struct
-		type t =
-			| UISImport
-			| UISTypo
-
-		let to_int = function
-			| UISImport -> 0
-			| UISTypo -> 1
-	end
-
-	open UnresolvedIdentifierSuggestion
 	open DiagnosticsKind
 	open DisplayTypes
 
@@ -596,72 +361,6 @@ module Diagnostics = struct
 				()
 		) com.types
 
-	let print_diagnostics ctx global =
-		let com = ctx.com in
-		let diag = Hashtbl.create 0 in
-		let add dk p sev args =
-			let file = Path.get_real_path p.pfile in
-			let diag = try
-				Hashtbl.find diag file
-			with Not_found ->
-				let d = DynArray.create() in
-				Hashtbl.add diag file d;
-				d
-			in
-			DynArray.add diag (dk,p,sev,args)
-		in
-		let add dk p sev args =
-			if global || is_display_file p.pfile then add dk p sev args
-		in
-		let find_type i =
-			let types = ref [] in
-			Hashtbl.iter (fun _ m ->
-				List.iter (fun mt ->
-					let s_full_type_path (p,s) n = s_type_path (p,s) ^ if (s <> n) then "." ^ n else "" in
-					let tinfos = t_infos mt in
-					if snd tinfos.mt_path = i then
-						types := JObject [
-							"kind",JInt (UnresolvedIdentifierSuggestion.to_int UISImport);
-							"name",JString (s_full_type_path m.m_path i)
-						] :: !types
-				) m.m_types;
-			) ctx.g.modules;
-			!types
-		in
-		List.iter (fun (s,p,suggestions) ->
-			let suggestions = List.map (fun (s,_) ->
-				JObject [
-					"kind",JInt (UnresolvedIdentifierSuggestion.to_int UISTypo);
-					"name",JString s
-				]
-			) suggestions in
-			add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (suggestions @ (find_type s));
-		) com.display_information.unresolved_identifiers;
-		PMap.iter (fun p (r,_) ->
-			if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning []
-		) com.shared.shared_display_information.import_positions;
-		List.iter (fun (s,p,sev) ->
-			add DKCompilerError p sev [JString s]
-		) com.shared.shared_display_information.diagnostics_messages;
-		let jl = Hashtbl.fold (fun file diag acc ->
-			let jl = DynArray.fold_left (fun acc (dk,p,sev,args) ->
-				(JObject [
-					"kind",JInt (to_int dk);
-					"severity",JInt (DiagnosticsSeverity.to_int sev);
-					"range",pos_to_json_range p;
-					"args",JArray args
-				]) :: acc
-			) [] diag in
-			(JObject [
-				"file",JString file;
-				"diagnostics",JArray jl
-			]) :: acc
-		) diag [] in
-		let js = JArray jl in
-		let b = Buffer.create 0 in
-		write_json (Buffer.add_string b) js;
-		Buffer.contents b
-
 	let is_diagnostics_run ctx = match ctx.com.display.dms_kind with
 		| DMDiagnostics true -> true
 		| DMDiagnostics false -> ctx.is_display_file
@@ -671,10 +370,63 @@ module Diagnostics = struct
 		if is_diagnostics_run ctx then mk (TMeta((Meta.Extern,[],e.epos),e)) e.etype e.epos else e
 end
 
-let maybe_mark_import_position ctx p =
-	if Diagnostics.is_diagnostics_run ctx then mark_import_position ctx.com p
+module ImportHandling = struct
+	type import_display_kind =
+		| IDKPackage of string list
+		| IDKModule of string list * string
+		| IDKSubType of string list * string * string
+		| IDKModuleField of string list * string * string
+		| IDKSubTypeField of string list * string * string * string
+		| IDK
+
+	type import_display = import_display_kind * pos
+
+	let convert_import_to_something_usable pt path =
+		let rec loop pack m t = function
+			| (s,p) :: l ->
+				let is_lower = is_lower_ident s in
+				let is_display_pos = encloses_position pt p in
+				begin match is_lower,m,t with
+					| _,None,Some _ ->
+						assert false (* impossible, I think *)
+					| true,Some m,None ->
+						if is_display_pos then (IDKModuleField(List.rev pack,m,s),p)
+						else (IDK,p) (* assume that we're done *)
+					| _,Some m,Some t ->
+						if is_display_pos then (IDKSubTypeField(List.rev pack,m,t,s),p)
+						else (IDK,p)
+					| true,None,None ->
+						if is_display_pos then (IDKPackage (List.rev (s :: pack)),p)
+						else loop (s :: pack) m t l
+					| false,Some sm,None ->
+						if is_display_pos then (IDKSubType (List.rev pack,sm,s),p)
+						else loop pack m (Some s) l
+					| false,None,None ->
+						if is_display_pos then (IDKModule (List.rev pack,s),p)
+						else loop pack (Some s) None l
+				end
+			| [] ->
+				(IDK,null_pos)
+		in
+		loop [] None None path
+
+	let add_import_position com p path =
+		com.shared.shared_display_information.import_positions <- PMap.add p (ref false,path) com.shared.shared_display_information.import_positions
+
+	let mark_import_position com p =
+		try
+			let r = fst (PMap.find p com.shared.shared_display_information.import_positions) in
+			r := true
+		with Not_found ->
+			()
+
+	let maybe_mark_import_position ctx p =
+		if Diagnostics.is_diagnostics_run ctx then mark_import_position ctx.com p
+end
 
 module Statistics = struct
+	open ImportHandling
+
 	type relation =
 		| Implemented
 		| Extended
@@ -846,7 +598,7 @@ module Statistics = struct
 				| _ -> ()
 			in
 			PMap.iter (fun p (_,path) ->
-				match convert_import_to_something_usable { p with pmin = p.pmax - 1; pmax = p.pmax - 1 } path,List.rev path with
+				match ImportHandling.convert_import_to_something_usable { p with pmin = p.pmax - 1; pmax = p.pmax - 1 } path,List.rev path with
 				| (IDKSubType(sl,s1,s2),_),(_,psubtype) :: (_,pmodule) :: _ ->
 					let m = check_module (sl,s1) pmodule in
 					(*ignore(check_subtype m s1 pmodule);*)
@@ -868,150 +620,6 @@ module Statistics = struct
 		symbols,relations
 end
 
-module StatisticsPrinter = struct
-	open Statistics
-
-	let relation_to_string = function
-		| Implemented -> "implementers"
-		| Extended -> "subclasses"
-		| Overridden -> "overrides"
-		| Referenced -> "references"
-
-	let symbol_to_string = function
-		| SKClass _ -> "class type"
-		| SKInterface _ -> "interface type"
-		| SKEnum _ -> "enum type"
-		| SKField _ -> "class field"
-		| SKEnumField _ -> "enum field"
-		| SKVariable _ -> "variable"
-
-	let print_statistics (kinds,relations) =
-		let files = Hashtbl.create 0 in
-		Hashtbl.iter (fun p rl ->
-			let file = Path.get_real_path p.pfile in
-			try
-				Hashtbl.replace files file ((p,rl) :: Hashtbl.find files file)
-			with Not_found ->
-				Hashtbl.add files file [p,rl]
-		) relations;
-		let ja = Hashtbl.fold (fun file relations acc ->
-			let l = List.map (fun (p,rl) ->
-				let h = Hashtbl.create 0 in
-				List.iter (fun (r,p) ->
-					let s = relation_to_string r in
-					let jo = JObject [
-						"range",pos_to_json_range p;
-						"file",JString (Path.get_real_path p.pfile);
-					] in
-					try Hashtbl.replace h s (jo :: Hashtbl.find h s)
-					with Not_found -> Hashtbl.add h s [jo]
-				) rl;
-				let l = Hashtbl.fold (fun s js acc -> (s,JArray js) :: acc) h [] in
-				let l = ("range",pos_to_json_range p) :: l in
-				let l = try ("kind",JString (symbol_to_string (Hashtbl.find kinds p))) :: l with Not_found -> l in
-				JObject l
-			) relations in
-			(JObject [
-				"file",JString file;
-				"statistics",JArray l
-			]) :: acc
-		) files [] in
-		let b = Buffer.create 0 in
-		write_json (Buffer.add_string b) (JArray ja);
-		Buffer.contents b
-end
-
-let process_display_file com classes =
-	let get_module_path_from_file_path com spath =
-		let rec loop = function
-			| [] -> None
-			| cp :: l ->
-				let cp = (if cp = "" then "./" else cp) in
-				let c = Path.add_trailing_slash (Path.get_real_path cp) in
-				let clen = String.length c in
-				if clen < String.length spath && String.sub spath 0 clen = c then begin
-					let path = String.sub spath clen (String.length spath - clen) in
-					(try
-						let path = Path.parse_type_path path in
-						(match loop l with
-						| Some x as r when String.length (Ast.s_type_path x) < String.length (Ast.s_type_path path) -> r
-						| _ -> Some path)
-					with _ -> loop l)
-				end else
-					loop l
-		in
-		loop com.class_path
-	in
-	match com.display.dms_display_file_policy with
-		| DFPNo ->
-			()
-		| dfp ->
-			if dfp = DFPOnly then begin
-				classes := [];
-				com.main_class <- None;
-			end;
-			let real = Path.get_real_path (!Parser.resume_display).Ast.pfile in
-			(match get_module_path_from_file_path com real with
-			| Some path ->
-				if com.display.dms_kind = DMPackage then raise (DisplayPackage (fst path));
-				classes := path :: !classes
-			| None ->
-				if not (Sys.file_exists real) then failwith "Display file does not exist";
-				(match List.rev (ExtString.String.nsplit real Path.path_sep) with
-				| file :: _ when file.[0] >= 'a' && file.[1] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
-				| _ -> ());
-				failwith "Display file was not found in class path"
-			);
-			Common.log com ("Display file : " ^ real);
-			Common.log com ("Classes found : ["  ^ (String.concat "," (List.map Ast.s_type_path !classes)) ^ "]")
-
-let process_global_display_mode com tctx = match com.display.dms_kind with
-	| DMUsage with_definition ->
-		let symbols,relations = Statistics.collect_statistics tctx in
-		let rec loop acc relations = match relations with
-			| (Statistics.Referenced,p) :: relations -> loop (p :: acc) relations
-			| _ :: relations -> loop acc relations
-			| [] -> acc
-		in
-		let usages = Hashtbl.fold (fun p sym acc ->
-			if Statistics.is_usage_symbol sym then begin
-				let acc = if with_definition then p :: acc else acc in
-				(try loop acc (Hashtbl.find relations p)
-				with Not_found -> acc)
-			end else
-				acc
-		) symbols [] in
-		let usages = List.sort (fun p1 p2 ->
-			let c = compare p1.pfile p2.pfile in
-			if c <> 0 then c else compare p1.pmin p2.pmin
-		) usages in
-		raise (DisplayPosition usages)
-	| DMDiagnostics global ->
-		Diagnostics.prepare com global;
-		raise (Diagnostics (Diagnostics.print_diagnostics tctx global))
-	| DMStatistics ->
-		let stats = Statistics.collect_statistics tctx in
-		raise (Statistics (StatisticsPrinter.print_statistics stats))
-	| DMModuleSymbols filter ->
-		let symbols = com.shared.shared_display_information.document_symbols in
-		let symbols = match !global_cache with
-			| None -> symbols
-			| Some cache ->
-				let rec loop acc com =
-					let com_sign = get_signature com in
-					let acc = Hashtbl.fold (fun (file,sign) (_,data) acc ->
-						if (filter <> None || is_display_file file) && com_sign = sign then
-							(file,DocumentSymbols.collect_module_symbols data) :: acc
-						else
-							acc
-					) cache.c_files acc in
-					match com.get_macros() with None -> acc | Some com -> loop acc com
-				in
-				loop symbols com
-		in
-		raise (ModuleSymbols(DocumentSymbols.print_module_symbols com symbols filter))
-	| _ -> ()
-
 module ToplevelCollector = struct
 	open IdentifierType
 
@@ -1173,35 +781,4 @@ module ToplevelCollector = struct
 		let cl = List.sort (fun (_,c1) (_,c2) -> compare c1 c2) cl in
 		let cl = StringError.filter_similar (fun (s,_) r -> r > 0 && r <= (min (String.length s) (String.length i)) / 3) cl in
 		ctx.com.display_information.unresolved_identifiers <- (i,p,cl) :: ctx.com.display_information.unresolved_identifiers
-end
-
-let display_signature tl display_arg =
-	let st = s_type (print_context()) in
-	let s_arg (n,o,t) = Printf.sprintf "%s%s:%s" (if o then "?" else "") n (st t) in
-	let s_fun args ret = Printf.sprintf "(%s):%s" (String.concat ", " (List.map s_arg args)) (st ret) in
-	let siginf = List.map (fun (t,doc) ->
-		let label = match follow t with TFun(args,ret) -> s_fun args ret | _ -> st t in
-		let parameters = match follow t with
-			| TFun(args,_) ->
-				List.map (fun arg ->
-					let label = s_arg arg in
-					JObject [
-						"label",JString label
-					]
-				) args
-			| _ -> []
-		in
-		let js = [
-			"label",JString label;
-			"parameters",JArray parameters;
-		] in
-		JObject (match doc with None -> js | Some s -> ("documentation",JString s) :: js)
-	) tl in
-	let jo = JObject [
-		"signatures",JArray siginf;
-		"activeParameter",JInt display_arg;
-		"activeSignature",JInt 0;
-	] in
-	let b = Buffer.create 0 in
-	write_json (Buffer.add_string b) jo;
-	Buffer.contents b
+end

+ 784 - 0
src/display/displayOutput.ml

@@ -0,0 +1,784 @@
+open Ast
+open Common
+open Common.DisplayMode
+open Type
+open Display
+open Typecore
+
+(* Old XML stuff *)
+
+let htmlescape s =
+	let s = String.concat "&amp;" (ExtString.String.nsplit s "&") in
+	let s = String.concat "&lt;" (ExtString.String.nsplit s "<") in
+	let s = String.concat "&gt;" (ExtString.String.nsplit s ">") in
+	let s = String.concat "&quot;" (ExtString.String.nsplit s "\"") in
+	s
+
+let get_timer_fields start_time =
+	let tot = ref 0. in
+	Hashtbl.iter (fun _ t -> tot := !tot +. t.total) Common.htimers;
+	let fields = [("@TOTAL", FKTimer (Printf.sprintf "%.3fs" (get_time() -. start_time)), "")] in
+	if !tot > 0. then
+		Hashtbl.fold (fun _ t acc ->
+			("@TIME " ^ t.name, FKTimer (Printf.sprintf "%.3fs (%.0f%%)" t.total (t.total *. 100. /. !tot)), "") :: acc
+		) Common.htimers fields
+	else
+		fields
+
+let print_keywords () =
+	let b = Buffer.create 0 in
+	Buffer.add_string b "<list>\n";
+	Hashtbl.iter (fun k _ ->
+		Buffer.add_string b (Printf.sprintf "<i n=\"%s\"></i>\n" k)
+	) Lexer.keywords;
+	Buffer.add_string b "</list>\n";
+	Buffer.contents b
+
+let print_fields fields =
+	let b = Buffer.create 0 in
+	Buffer.add_string b "<list>\n";
+	List.iter (fun (n,k,d) ->
+		let s_kind, t = match k with
+			| FKVar t -> "var", s_type (print_context()) t
+			| FKMethod t -> "method", s_type (print_context()) t
+			| FKType t -> "type", s_type (print_context()) t
+			| FKPackage -> "package", ""
+			| FKModule -> "type", ""
+			| FKMetadata -> "metadata", ""
+			| FKTimer s -> "", s
+		in
+		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))
+	) (List.sort (fun (a,ak,_) (b,bk,_) -> compare (display_field_kind_index ak,a) (display_field_kind_index bk,b)) fields);
+	Buffer.add_string b "</list>\n";
+	Buffer.contents b
+
+let maybe_print_doc d =
+	Option.map_default (fun s -> Printf.sprintf " d=\"%s\"" (htmlescape s)) "" d
+
+let print_toplevel il =
+	let b = Buffer.create 0 in
+	Buffer.add_string b "<il>\n";
+	let s_type t = htmlescape (s_type (print_context()) t) in
+	let s_doc d = maybe_print_doc d in
+	List.iter (fun id -> match id with
+		| IdentifierType.ITLocal v ->
+			Buffer.add_string b (Printf.sprintf "<i k=\"local\" t=\"%s\">%s</i>\n" (s_type v.v_type) v.v_name);
+		| IdentifierType.ITMember(c,cf) ->
+			Buffer.add_string b (Printf.sprintf "<i k=\"member\" t=\"%s\"%s>%s</i>\n" (s_type cf.cf_type) (s_doc cf.cf_doc) cf.cf_name);
+		| IdentifierType.ITStatic(c,cf) ->
+			Buffer.add_string b (Printf.sprintf "<i k=\"static\" t=\"%s\"%s>%s</i>\n" (s_type cf.cf_type) (s_doc cf.cf_doc) cf.cf_name);
+		| IdentifierType.ITEnum(en,ef) ->
+			Buffer.add_string b (Printf.sprintf "<i k=\"enum\" t=\"%s\"%s>%s</i>\n" (s_type ef.ef_type) (s_doc ef.ef_doc) ef.ef_name);
+		| IdentifierType.ITEnumAbstract(a,cf) ->
+			Buffer.add_string b (Printf.sprintf "<i k=\"enumabstract\" t=\"%s\"%s>%s</i>\n" (s_type cf.cf_type) (s_doc cf.cf_doc) cf.cf_name);
+		| IdentifierType.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);
+		| IdentifierType.ITType(mt) ->
+			let infos = t_infos mt in
+			Buffer.add_string b (Printf.sprintf "<i k=\"type\" p=\"%s\"%s>%s</i>\n" (s_type_path infos.mt_path) (s_doc infos.mt_doc) (snd infos.mt_path));
+		| IdentifierType.ITPackage s ->
+			Buffer.add_string b (Printf.sprintf "<i k=\"package\">%s</i>\n" s)
+	) il;
+	Buffer.add_string b "</il>";
+	Buffer.contents b
+
+let print_type t p doc =
+	let b = Buffer.create 0 in
+	if p = null_pos then
+		Buffer.add_string b "<type"
+	else begin
+		let error_printer file line = Printf.sprintf "%s:%d:" (Path.unique_full_path file) line in
+		let epos = Lexer.get_error_pos error_printer p in
+		Buffer.add_string b ("<type p=\"" ^ (htmlescape epos) ^ "\"")
+	end;
+	Buffer.add_string b (maybe_print_doc doc);
+	Buffer.add_string b ">\n";
+	Buffer.add_string b (htmlescape (s_type (print_context()) t));
+	Buffer.add_string b "\n</type>\n";
+	Buffer.contents b
+
+let print_signatures tl =
+	let b = Buffer.create 0 in
+	List.iter (fun (t,doc) ->
+		Buffer.add_string b "<type";
+		Option.may (fun s -> Buffer.add_string b (Printf.sprintf " d=\"%s\"" (htmlescape s))) doc;
+		Buffer.add_string b ">\n";
+		Buffer.add_string b (htmlescape (s_type (print_context()) (follow t)));
+		Buffer.add_string b "\n</type>\n";
+	) tl;
+	Buffer.contents b
+
+let print_positions pl =
+	let b = Buffer.create 0 in
+	let error_printer file line = Printf.sprintf "%s:%d:" (Path.get_real_path file) line in
+	Buffer.add_string b "<list>\n";
+	List.iter (fun p ->
+		let epos = Lexer.get_error_pos error_printer p in
+		Buffer.add_string b "<pos>";
+		Buffer.add_string b epos;
+		Buffer.add_string b "</pos>\n";
+	) pl;
+	Buffer.add_string b "</list>";
+	Buffer.contents b
+
+
+let display_memory com =
+	let verbose = com.verbose in
+	let print = print_endline in
+	let fmt_size sz =
+		if sz < 1024 then
+			string_of_int sz ^ " B"
+		else if sz < 1024*1024 then
+			string_of_int (sz asr 10) ^ " KB"
+		else
+			Printf.sprintf "%.1f MB" ((float_of_int sz) /. (1024.*.1024.))
+	in
+	let size v =
+		fmt_size (mem_size v)
+	in
+	Gc.full_major();
+	Gc.compact();
+	let mem = Gc.stat() in
+	print ("Total Allocated Memory " ^ fmt_size (mem.Gc.heap_words * (Sys.word_size asr 8)));
+	print ("Free Memory " ^ fmt_size (mem.Gc.free_words * (Sys.word_size asr 8)));
+	(match !global_cache with
+	| None ->
+		print "No cache found";
+	| Some c ->
+		print ("Total cache size " ^ size c);
+		print ("  haxelib " ^ size c.c_haxelib);
+		print ("  parsed ast " ^ size c.c_files ^ " (" ^ string_of_int (Hashtbl.length c.c_files) ^ " files stored)");
+		print ("  typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)");
+		let rec scan_module_deps m h =
+			if Hashtbl.mem h m.m_id then
+				()
+			else begin
+				Hashtbl.add h m.m_id m;
+				PMap.iter (fun _ m -> scan_module_deps m h) m.m_extra.m_deps
+			end
+		in
+		let all_modules = Hashtbl.fold (fun _ m acc -> PMap.add m.m_id m acc) c.c_modules PMap.empty in
+		let modules = Hashtbl.fold (fun (path,key) m acc ->
+			let mdeps = Hashtbl.create 0 in
+			scan_module_deps m mdeps;
+			let deps = ref [] in
+			let out = ref all_modules in
+			Hashtbl.iter (fun _ md ->
+				out := PMap.remove md.m_id !out;
+				if m == md then () else begin
+				deps := Obj.repr md :: !deps;
+				List.iter (fun t ->
+					match t with
+					| TClassDecl c ->
+						deps := Obj.repr c :: !deps;
+						List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_statics;
+						List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_fields;
+					| TEnumDecl e ->
+						deps := Obj.repr e :: !deps;
+						List.iter (fun n -> deps := Obj.repr (PMap.find n e.e_constrs) :: !deps) e.e_names;
+					| TTypeDecl t -> deps := Obj.repr t :: !deps;
+					| TAbstractDecl a -> deps := Obj.repr a :: !deps;
+				) md.m_types;
+				end
+			) mdeps;
+			let chk = Obj.repr Common.memory_marker :: PMap.fold (fun m acc -> Obj.repr m :: acc) !out [] in
+			let inf = Objsize.objsize m !deps chk in
+			(m,Objsize.size_with_headers inf, (inf.Objsize.reached,!deps,!out)) :: acc
+		) c.c_modules [] in
+		let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in
+		List.iter (fun (m,size,(reached,deps,out)) ->
+			let key = m.m_extra.m_sign in
+			if key <> !cur_key then begin
+				print (Printf.sprintf ("    --- CONFIG %s ----------------------------") (Digest.to_hex key));
+				cur_key := key;
+			end;
+			let sign md =
+				if md.m_extra.m_sign = key then "" else "(" ^ (try Digest.to_hex md.m_extra.m_sign with _ -> "???" ^ md.m_extra.m_sign) ^ ")"
+			in
+			print (Printf.sprintf "    %s : %s" (Ast.s_type_path m.m_path) (fmt_size size));
+			(if reached then try
+				incr mcount;
+				let lcount = ref 0 in
+				let leak l =
+					incr lcount;
+					incr tcount;
+					print (Printf.sprintf "      LEAK %s" l);
+					if !lcount >= 3 && !tcount >= 100 && not verbose then begin
+						print (Printf.sprintf "      ...");
+						raise Exit;
+					end;
+				in
+				if (Objsize.objsize m deps [Obj.repr Common.memory_marker]).Objsize.reached then leak "common";
+				PMap.iter (fun _ md ->
+					if (Objsize.objsize m deps [Obj.repr md]).Objsize.reached then leak (Ast.s_type_path md.m_path ^ sign md);
+				) out;
+			with Exit ->
+				());
+			if verbose then begin
+				print (Printf.sprintf "      %d total deps" (List.length deps));
+				PMap.iter (fun _ md ->
+					print (Printf.sprintf "      dep %s%s" (Ast.s_type_path md.m_path) (sign md));
+				) m.m_extra.m_deps;
+			end;
+			flush stdout
+		) (List.sort (fun (m1,s1,_) (m2,s2,_) ->
+			let k1 = m1.m_extra.m_sign and k2 = m2.m_extra.m_sign in
+			if k1 = k2 then s1 - s2 else if k1 > k2 then 1 else -1
+		) modules);
+		if !mcount > 0 then print ("*** " ^ string_of_int !mcount ^ " modules have leaks !");
+		print "Cache dump complete")
+
+module TypePathHandler = struct
+	let unique l =
+		let rec _unique = function
+			| [] -> []
+			| x1 :: x2 :: l when x1 = x2 -> _unique (x2 :: l)
+			| x :: l -> x :: _unique l
+		in
+		_unique (List.sort compare l)
+
+	let rec read_type_path com p =
+		let classes = ref [] in
+		let packages = ref [] in
+		let p = (match p with
+			| x :: l ->
+				(try
+					match PMap.find x com.package_rules with
+					| Remap s -> s :: l
+					| _ -> p
+				with
+					Not_found -> p)
+			| _ -> p
+		) in
+		List.iter (fun path ->
+			let dir = path ^ String.concat "/" p in
+			let r = (try Sys.readdir dir with _ -> [||]) in
+			Array.iter (fun f ->
+				if (try (Unix.stat (dir ^ "/" ^ f)).Unix.st_kind = Unix.S_DIR with _ -> false) then begin
+					if f.[0] >= 'a' && f.[0] <= 'z' then begin
+						if p = ["."] then
+							match read_type_path com [f] with
+							| [] , [] -> ()
+							| _ ->
+								try
+									match PMap.find f com.package_rules with
+									| Forbidden -> ()
+									| Remap f -> packages := f :: !packages
+								with Not_found ->
+									packages := f :: !packages
+						else
+							packages := f :: !packages
+					end;
+				end else if file_extension f = "hx" then begin
+					let c = Filename.chop_extension f in
+					if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
+				end;
+			) r;
+		) com.class_path;
+		List.iter (fun (_,_,extract) ->
+			Hashtbl.iter (fun (path,name) _ ->
+				if path = p then classes := name :: !classes else
+				let rec loop p1 p2 =
+					match p1, p2 with
+					| [], _ -> ()
+					| x :: _, [] -> packages := x :: !packages
+					| a :: p1, b :: p2 -> if a = b then loop p1 p2
+				in
+				loop path p
+			) (extract());
+		) com.swf_libs;
+		List.iter (fun (path,std,close,all_files,lookup) ->
+			List.iter (fun (path, name) ->
+				if path = p then classes := name :: !classes else
+				let rec loop p1 p2 =
+					match p1, p2 with
+					| [], _ -> ()
+					| x :: _, [] -> packages := x :: !packages
+					| a :: p1, b :: p2 -> if a = b then loop p1 p2
+				in
+				loop path p
+			) (all_files())
+		) com.java_libs;
+		List.iter (fun (path,std,all_files,lookup) ->
+			List.iter (fun (path, name) ->
+				if path = p then classes := name :: !classes else
+				let rec loop p1 p2 =
+					match p1, p2 with
+					| [], _ -> ()
+					| x :: _, [] -> packages := x :: !packages
+					| a :: p1, b :: p2 -> if a = b then loop p1 p2
+				in
+			loop path p
+			) (all_files())
+		) com.net_libs;
+		unique !packages, unique !classes
+
+	(** raise field completion listing packages and modules in a given package *)
+	let complete_type_path com p =
+		let packs, modules = read_type_path com p in
+		if packs = [] && modules = [] then
+			(error ("No classes found in " ^ String.concat "." p) Ast.null_pos)
+		else
+			let packs = List.map (fun n -> n,Display.FKPackage,"") packs in
+			let modules = List.map (fun n -> n,Display.FKModule,"") modules in
+			Some (packs @ modules)
+
+	(** raise field completion listing module sub-types and static fields *)
+	let complete_type_path_inner com p c cur_package is_import =
+		try
+			let sl_pack,s_module = match List.rev p with
+				| s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s
+				| _ -> p,c
+			in
+			let ctx = Typer.create com in
+			let rec lookup p =
+				try
+					Typeload.load_module ctx (p,s_module) Ast.null_pos
+				with e ->
+					if cur_package then
+						match List.rev p with
+						| [] -> raise e
+						| _ :: p -> lookup (List.rev p)
+					else
+						raise e
+			in
+			let m = lookup sl_pack in
+			let statics = ref None in
+			let public_types = List.filter (fun t ->
+				let tinfos = t_infos t in
+				let is_module_type = snd tinfos.mt_path = c in
+				if is_import && is_module_type then begin match t with
+					| TClassDecl c ->
+						ignore(c.cl_build());
+						statics := Some c.cl_ordered_statics
+					| _ -> ()
+				end;
+				not tinfos.mt_private
+			) m.m_types in
+			let types =
+				if c <> s_module then
+					[]
+				else
+					List.map (fun t ->
+						let infos = t_infos t in
+						(snd infos.mt_path), Display.FKModule, (Option.default "" infos.mt_doc)
+					) public_types
+			in
+			let make_field_doc cf =
+				cf.cf_name,
+				(match cf.cf_kind with Method _ -> Display.FKMethod cf.cf_type | Var _ -> Display.FKVar cf.cf_type),
+				(match cf.cf_doc with Some s -> s | None -> "")
+			in
+			let fields = match !statics with
+				| None -> types
+				| Some cfl -> types @ (List.map make_field_doc (List.filter (fun cf -> cf.cf_public) cfl))
+			in
+			Some fields
+		with _ ->
+			error ("Could not load module " ^ (Ast.s_type_path (p,c))) Ast.null_pos
+end
+
+(* New JSON stuff *)
+
+open Json
+
+(** return a range JSON structure for given position
+    positions are 0-based and the result object looks like this:
+    {
+        start: {line: 0, character: 0},
+        end: {line: 3, character: 42},
+    }
+*)
+let pos_to_json_range p =
+	if p.pmin = -1 then
+		JNull
+	else
+		let l1, p1, l2, p2 = Lexer.get_pos_coords p in
+		let to_json l c = JObject [("line", JInt (l - 1)); ("character", JInt c)] in
+		JObject [
+			("start", to_json l1 p1);
+			("end", to_json l2 p2);
+		]
+
+let print_signature tl display_arg =
+	let st = s_type (print_context()) in
+	let s_arg (n,o,t) = Printf.sprintf "%s%s:%s" (if o then "?" else "") n (st t) in
+	let s_fun args ret = Printf.sprintf "(%s):%s" (String.concat ", " (List.map s_arg args)) (st ret) in
+	let siginf = List.map (fun (t,doc) ->
+		let label = match follow t with TFun(args,ret) -> s_fun args ret | _ -> st t in
+		let parameters = match follow t with
+			| TFun(args,_) ->
+				List.map (fun arg ->
+					let label = s_arg arg in
+					JObject [
+						"label",JString label
+					]
+				) args
+			| _ -> []
+		in
+		let js = [
+			"label",JString label;
+			"parameters",JArray parameters;
+		] in
+		JObject (match doc with None -> js | Some s -> ("documentation",JString s) :: js)
+	) tl in
+	let jo = JObject [
+		"signatures",JArray siginf;
+		"activeParameter",JInt display_arg;
+		"activeSignature",JInt 0;
+	] in
+	let b = Buffer.create 0 in
+	write_json (Buffer.add_string b) jo;
+	Buffer.contents b
+
+module StatisticsPrinter = struct
+	open Statistics
+
+	let relation_to_string = function
+		| Implemented -> "implementers"
+		| Extended -> "subclasses"
+		| Overridden -> "overrides"
+		| Referenced -> "references"
+
+	let symbol_to_string = function
+		| SKClass _ -> "class type"
+		| SKInterface _ -> "interface type"
+		| SKEnum _ -> "enum type"
+		| SKField _ -> "class field"
+		| SKEnumField _ -> "enum field"
+		| SKVariable _ -> "variable"
+
+	let print_statistics (kinds,relations) =
+		let files = Hashtbl.create 0 in
+		Hashtbl.iter (fun p rl ->
+			let file = Path.get_real_path p.pfile in
+			try
+				Hashtbl.replace files file ((p,rl) :: Hashtbl.find files file)
+			with Not_found ->
+				Hashtbl.add files file [p,rl]
+		) relations;
+		let ja = Hashtbl.fold (fun file relations acc ->
+			let l = List.map (fun (p,rl) ->
+				let h = Hashtbl.create 0 in
+				List.iter (fun (r,p) ->
+					let s = relation_to_string r in
+					let jo = JObject [
+						"range",pos_to_json_range p;
+						"file",JString (Path.get_real_path p.pfile);
+					] in
+					try Hashtbl.replace h s (jo :: Hashtbl.find h s)
+					with Not_found -> Hashtbl.add h s [jo]
+				) rl;
+				let l = Hashtbl.fold (fun s js acc -> (s,JArray js) :: acc) h [] in
+				let l = ("range",pos_to_json_range p) :: l in
+				let l = try ("kind",JString (symbol_to_string (Hashtbl.find kinds p))) :: l with Not_found -> l in
+				JObject l
+			) relations in
+			(JObject [
+				"file",JString file;
+				"statistics",JArray l
+			]) :: acc
+		) files [] in
+		let b = Buffer.create 0 in
+		write_json (Buffer.add_string b) (JArray ja);
+		Buffer.contents b
+end
+
+module DiagnosticsPrinter = struct
+	open Diagnostics
+	open Diagnostics.DiagnosticsKind
+	open DisplayTypes
+
+	type t = DiagnosticsKind.t * pos
+
+	module UnresolvedIdentifierSuggestion = struct
+		type t =
+			| UISImport
+			| UISTypo
+
+		let to_int = function
+			| UISImport -> 0
+			| UISTypo -> 1
+	end
+
+	let print_diagnostics ctx global =
+		let com = ctx.com in
+		let diag = Hashtbl.create 0 in
+		let add dk p sev args =
+			let file = Path.get_real_path p.pfile in
+			let diag = try
+				Hashtbl.find diag file
+			with Not_found ->
+				let d = DynArray.create() in
+				Hashtbl.add diag file d;
+				d
+			in
+			DynArray.add diag (dk,p,sev,args)
+		in
+		let add dk p sev args =
+			if global || is_display_file p.pfile then add dk p sev args
+		in
+		let find_type i =
+			let types = ref [] in
+			Hashtbl.iter (fun _ m ->
+				List.iter (fun mt ->
+					let s_full_type_path (p,s) n = s_type_path (p,s) ^ if (s <> n) then "." ^ n else "" in
+					let tinfos = t_infos mt in
+					if snd tinfos.mt_path = i then
+						types := JObject [
+							"kind",JInt (UnresolvedIdentifierSuggestion.to_int UnresolvedIdentifierSuggestion.UISImport);
+							"name",JString (s_full_type_path m.m_path i)
+						] :: !types
+				) m.m_types;
+			) ctx.g.modules;
+			!types
+		in
+		List.iter (fun (s,p,suggestions) ->
+			let suggestions = List.map (fun (s,_) ->
+				JObject [
+					"kind",JInt (UnresolvedIdentifierSuggestion.to_int UnresolvedIdentifierSuggestion.UISTypo);
+					"name",JString s
+				]
+			) suggestions in
+			add DKUnresolvedIdentifier p DiagnosticsSeverity.Error (suggestions @ (find_type s));
+		) com.display_information.unresolved_identifiers;
+		PMap.iter (fun p (r,_) ->
+			if not !r then add DKUnusedImport p DiagnosticsSeverity.Warning []
+		) com.shared.shared_display_information.import_positions;
+		List.iter (fun (s,p,sev) ->
+			add DKCompilerError p sev [JString s]
+		) com.shared.shared_display_information.diagnostics_messages;
+		let jl = Hashtbl.fold (fun file diag acc ->
+			let jl = DynArray.fold_left (fun acc (dk,p,sev,args) ->
+				(JObject [
+					"kind",JInt (to_int dk);
+					"severity",JInt (DiagnosticsSeverity.to_int sev);
+					"range",pos_to_json_range p;
+					"args",JArray args
+				]) :: acc
+			) [] diag in
+			(JObject [
+				"file",JString file;
+				"diagnostics",JArray jl
+			]) :: acc
+		) diag [] in
+		let js = JArray jl in
+		let b = Buffer.create 0 in
+		write_json (Buffer.add_string b) js;
+		Buffer.contents b
+end
+
+module ModuleSymbolsPrinter = struct
+	open DisplayTypes.SymbolKind
+	open DisplayTypes.SymbolInformation
+
+	let print_module_symbols com symbols filter =
+		let regex = Option.map Str.regexp_case_fold filter in
+		let reported = Hashtbl.create 0 in
+		let add si =
+			if Hashtbl.mem reported si.pos then false
+			else begin
+				let b = match regex with
+					| None -> true
+					| Some regex -> (try ignore(Str.search_forward regex si.name 0); true with Not_found -> false)
+				in
+				Hashtbl.replace reported si.pos true;
+				b
+			end
+		in
+		let ja = List.fold_left (fun acc (file,l) ->
+			let jl = ExtList.List.filter_map (fun si ->
+				if not (add si) then
+					None
+				else begin
+					let l =
+						("name",JString si.name) ::
+						("kind",JInt (to_int si.kind)) ::
+						("range", pos_to_json_range si.pos) ::
+						(match si.container_name with None -> [] | Some s -> ["containerName",JString s])
+					in
+					Some (JObject l)
+				end
+			) (DynArray.to_list l) in
+			if jl = [] then
+				acc
+			else
+				(JObject [
+					"file",JString file;
+					"symbols",JArray jl
+				]) :: acc
+		) [] symbols in
+		let js = JArray ja in
+		let b = Buffer.create 0 in
+		write_json (Buffer.add_string b) js;
+		Buffer.contents b
+end
+
+(* Mode processing *)
+
+exception Completion of string
+
+let unquote v =
+	let len = String.length v in
+	if len > 0 && v.[0] = '"' && v.[len - 1] = '"' then String.sub v 1 (len - 2) else v
+
+let handle_display_argument com file_pos pre_compilation did_something =
+	match file_pos with
+	| "classes" ->
+		pre_compilation := (fun() -> raise (Parser.TypePath (["."],None,true))) :: !pre_compilation;
+	| "keywords" ->
+		raise (Completion (print_keywords ()))
+	| "memory" ->
+		did_something := true;
+		(try display_memory com with e -> prerr_endline (Printexc.get_backtrace ()));
+	| "diagnostics" ->
+		Common.define com Define.NoCOpt;
+		com.display <- DisplayMode.create (DMDiagnostics true);
+		Common.display_default := DMDiagnostics true;
+	| _ ->
+		let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in
+		let file = unquote file in
+		let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
+		let mode = match smode with
+			| "position" ->
+				Common.define com Define.NoCOpt;
+				DMPosition
+			| "usage" ->
+				Common.define com Define.NoCOpt;
+				DMUsage false
+			(*| "rename" ->
+				Common.define com Define.NoCOpt;
+				DMUsage true*)
+			| "package" ->
+				DMPackage
+			| "type" ->
+				Common.define com Define.NoCOpt;
+				DMType
+			| "toplevel" ->
+				Common.define com Define.NoCOpt;
+				DMToplevel
+			| "module-symbols" ->
+				Common.define com Define.NoCOpt;
+				DMModuleSymbols None;
+			| "diagnostics" ->
+				Common.define com Define.NoCOpt;
+				DMDiagnostics false;
+			| "statistics" ->
+				Common.define com Define.NoCOpt;
+				DMStatistics
+			| "signature" ->
+				DMSignature
+			| "" ->
+				DMDefault
+			| _ ->
+				let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in
+				match smode with
+					| "resolve" ->
+						DMResolve arg
+					| "workspace-symbols" ->
+						Common.define com Define.NoCOpt;
+						DMModuleSymbols (Some arg)
+					| _ ->
+						DMDefault
+		in
+		let pos = try int_of_string pos with _ -> failwith ("Invalid format : "  ^ pos) in
+		com.display <- DisplayMode.create mode;
+		Common.display_default := mode;
+		Common.define_value com Define.Display (if smode <> "" then smode else "1");
+		Parser.use_doc := true;
+		Parser.resume_display := {
+			Ast.pfile = Path.unique_full_path file;
+			Ast.pmin = pos;
+			Ast.pmax = pos;
+		}
+
+let process_display_file com classes =
+	let get_module_path_from_file_path com spath =
+		let rec loop = function
+			| [] -> None
+			| cp :: l ->
+				let cp = (if cp = "" then "./" else cp) in
+				let c = Path.add_trailing_slash (Path.get_real_path cp) in
+				let clen = String.length c in
+				if clen < String.length spath && String.sub spath 0 clen = c then begin
+					let path = String.sub spath clen (String.length spath - clen) in
+					(try
+						let path = Path.parse_type_path path in
+						(match loop l with
+						| Some x as r when String.length (Ast.s_type_path x) < String.length (Ast.s_type_path path) -> r
+						| _ -> Some path)
+					with _ -> loop l)
+				end else
+					loop l
+		in
+		loop com.class_path
+	in
+	match com.display.dms_display_file_policy with
+		| DFPNo ->
+			()
+		| dfp ->
+			if dfp = DFPOnly then begin
+				classes := [];
+				com.main_class <- None;
+			end;
+			let real = Path.get_real_path (!Parser.resume_display).Ast.pfile in
+			(match get_module_path_from_file_path com real with
+			| Some path ->
+				if com.display.dms_kind = DMPackage then raise (DisplayPackage (fst path));
+				classes := path :: !classes
+			| None ->
+				if not (Sys.file_exists real) then failwith "Display file does not exist";
+				(match List.rev (ExtString.String.nsplit real Path.path_sep) with
+				| file :: _ when file.[0] >= 'a' && file.[1] <= 'z' -> failwith ("Display file '" ^ file ^ "' should not start with a lowercase letter")
+				| _ -> ());
+				failwith "Display file was not found in class path"
+			);
+			Common.log com ("Display file : " ^ real);
+			Common.log com ("Classes found : ["  ^ (String.concat "," (List.map Ast.s_type_path !classes)) ^ "]")
+
+let process_global_display_mode com tctx = match com.display.dms_kind with
+	| DMUsage with_definition ->
+		let symbols,relations = Statistics.collect_statistics tctx in
+		let rec loop acc relations = match relations with
+			| (Statistics.Referenced,p) :: relations -> loop (p :: acc) relations
+			| _ :: relations -> loop acc relations
+			| [] -> acc
+		in
+		let usages = Hashtbl.fold (fun p sym acc ->
+			if Statistics.is_usage_symbol sym then begin
+				let acc = if with_definition then p :: acc else acc in
+				(try loop acc (Hashtbl.find relations p)
+				with Not_found -> acc)
+			end else
+				acc
+		) symbols [] in
+		let usages = List.sort (fun p1 p2 ->
+			let c = compare p1.pfile p2.pfile in
+			if c <> 0 then c else compare p1.pmin p2.pmin
+		) usages in
+		raise (DisplayPosition usages)
+	| DMDiagnostics global ->
+		Diagnostics.prepare com global;
+		raise (Diagnostics (DiagnosticsPrinter.print_diagnostics tctx global))
+	| DMStatistics ->
+		let stats = Statistics.collect_statistics tctx in
+		raise (Statistics (StatisticsPrinter.print_statistics stats))
+	| DMModuleSymbols filter ->
+		let symbols = com.shared.shared_display_information.document_symbols in
+		let symbols = match !global_cache with
+			| None -> symbols
+			| Some cache ->
+				let rec loop acc com =
+					let com_sign = get_signature com in
+					let acc = Hashtbl.fold (fun (file,sign) (_,data) acc ->
+						if (filter <> None || is_display_file file) && com_sign = sign then
+							(file,DocumentSymbols.collect_module_symbols data) :: acc
+						else
+							acc
+					) cache.c_files acc in
+					match com.get_macros() with None -> acc | Some com -> loop acc com
+				in
+				loop symbols com
+		in
+		raise (ModuleSymbols(ModuleSymbolsPrinter.print_module_symbols com symbols filter))
+	| _ -> ()

+ 21 - 342
src/main.ml

@@ -114,157 +114,6 @@ let reserved_flags = [
 	"as3";"swc";"macro";"sys"
 	]
 
-let unique l =
-	let rec _unique = function
-		| [] -> []
-		| x1 :: x2 :: l when x1 = x2 -> _unique (x2 :: l)
-		| x :: l -> x :: _unique l
-	in
-	_unique (List.sort compare l)
-
-let rec read_type_path com p =
-	let classes = ref [] in
-	let packages = ref [] in
-	let p = (match p with
-		| x :: l ->
-			(try
-				match PMap.find x com.package_rules with
-				| Remap s -> s :: l
-				| _ -> p
-			with
-				Not_found -> p)
-		| _ -> p
-	) in
-	List.iter (fun path ->
-		let dir = path ^ String.concat "/" p in
-		let r = (try Sys.readdir dir with _ -> [||]) in
-		Array.iter (fun f ->
-			if (try (Unix.stat (dir ^ "/" ^ f)).Unix.st_kind = Unix.S_DIR with _ -> false) then begin
-				if f.[0] >= 'a' && f.[0] <= 'z' then begin
-					if p = ["."] then
-						match read_type_path com [f] with
-						| [] , [] -> ()
-						| _ ->
-							try
-								match PMap.find f com.package_rules with
-								| Forbidden -> ()
-								| Remap f -> packages := f :: !packages
-							with Not_found ->
-								packages := f :: !packages
-					else
-						packages := f :: !packages
-				end;
-			end else if file_extension f = "hx" then begin
-				let c = Filename.chop_extension f in
-				if String.length c < 2 || String.sub c (String.length c - 2) 2 <> "__" then classes := c :: !classes;
-			end;
-		) r;
-	) com.class_path;
-	List.iter (fun (_,_,extract) ->
-		Hashtbl.iter (fun (path,name) _ ->
-			if path = p then classes := name :: !classes else
-			let rec loop p1 p2 =
-				match p1, p2 with
-				| [], _ -> ()
-				| x :: _, [] -> packages := x :: !packages
-				| a :: p1, b :: p2 -> if a = b then loop p1 p2
-			in
-			loop path p
-		) (extract());
-	) com.swf_libs;
-	List.iter (fun (path,std,close,all_files,lookup) ->
-		List.iter (fun (path, name) ->
-			if path = p then classes := name :: !classes else
-			let rec loop p1 p2 =
-				match p1, p2 with
-				| [], _ -> ()
-				| x :: _, [] -> packages := x :: !packages
-				| a :: p1, b :: p2 -> if a = b then loop p1 p2
-			in
-			loop path p
-		) (all_files())
-	) com.java_libs;
-	List.iter (fun (path,std,all_files,lookup) ->
-		List.iter (fun (path, name) ->
-			if path = p then classes := name :: !classes else
-			let rec loop p1 p2 =
-				match p1, p2 with
-				| [], _ -> ()
-				| x :: _, [] -> packages := x :: !packages
-				| a :: p1, b :: p2 -> if a = b then loop p1 p2
-			in
-		loop path p
-		) (all_files())
-	) com.net_libs;
-	unique !packages, unique !classes
-
-(** raise field completion listing packages and modules in a given package *)
-let complete_type_path ctx p =
-	let packs, modules = read_type_path ctx.com p in
-	if packs = [] && modules = [] then
-		(error ctx ("No classes found in " ^ String.concat "." p) Ast.null_pos;
-		None)
-	else
-		let packs = List.map (fun n -> n,Display.FKPackage,"") packs in
-		let modules = List.map (fun n -> n,Display.FKModule,"") modules in
-		Some (packs @ modules)
-
-(** raise field completion listing module sub-types and static fields *)
-let complete_type_path_inner ctx p c cur_package is_import =
-	let com = ctx.com in
-	try
-		let sl_pack,s_module = match List.rev p with
-			| s :: sl when s.[0] >= 'A' && s.[0] <= 'Z' -> List.rev sl,s
-			| _ -> p,c
-		in
-		let ctx = Typer.create com in
-		let rec lookup p =
-			try
-				Typeload.load_module ctx (p,s_module) Ast.null_pos
-			with e ->
-				if cur_package then
-					match List.rev p with
-					| [] -> raise e
-					| _ :: p -> lookup (List.rev p)
-				else
-					raise e
-		in
-		let m = lookup sl_pack in
-		let statics = ref None in
-		let public_types = List.filter (fun t ->
-			let tinfos = t_infos t in
-			let is_module_type = snd tinfos.mt_path = c in
-			if is_import && is_module_type then begin match t with
-				| TClassDecl c ->
-					ignore(c.cl_build());
-					statics := Some c.cl_ordered_statics
-				| _ -> ()
-			end;
-			not tinfos.mt_private
-		) m.m_types in
-		let types =
-			if c <> s_module then
-				[]
-			else
-				List.map (fun t ->
-					let infos = t_infos t in
-					(snd infos.mt_path), Display.FKModule, (Option.default "" infos.mt_doc)
-				) public_types
-		in
-		let make_field_doc cf =
-			cf.cf_name,
-			(match cf.cf_kind with Method _ -> Display.FKMethod cf.cf_type | Var _ -> Display.FKVar cf.cf_type),
-			(match cf.cf_doc with Some s -> s | None -> "")
-		in
-		let fields = match !statics with
-			| None -> types
-			| Some cfl -> types @ (List.map make_field_doc (List.filter (fun cf -> cf.cf_public) cfl))
-		in
-		Some fields
-	with _ ->
-		error ctx ("Could not load module " ^ (Ast.s_type_path (p,c))) Ast.null_pos;
-		None
-
 let delete_file f = try Sys.remove f with _ -> ()
 
 let expand_env ?(h=None) path  =
@@ -393,112 +242,6 @@ let run_command ctx cmd =
 	t();
 	r
 
-let display_memory ctx =
-	let verbose = ctx.com.verbose in
-	let print = print_endline in
-	let fmt_size sz =
-		if sz < 1024 then
-			string_of_int sz ^ " B"
-		else if sz < 1024*1024 then
-			string_of_int (sz asr 10) ^ " KB"
-		else
-			Printf.sprintf "%.1f MB" ((float_of_int sz) /. (1024.*.1024.))
-	in
-	let size v =
-		fmt_size (mem_size v)
-	in
-	Gc.full_major();
-	Gc.compact();
-	let mem = Gc.stat() in
-	print ("Total Allocated Memory " ^ fmt_size (mem.Gc.heap_words * (Sys.word_size asr 8)));
-	print ("Free Memory " ^ fmt_size (mem.Gc.free_words * (Sys.word_size asr 8)));
-	(match !global_cache with
-	| None ->
-		print "No cache found";
-	| Some c ->
-		print ("Total cache size " ^ size c);
-		print ("  haxelib " ^ size c.c_haxelib);
-		print ("  parsed ast " ^ size c.c_files ^ " (" ^ string_of_int (Hashtbl.length c.c_files) ^ " files stored)");
-		print ("  typed modules " ^ size c.c_modules ^ " (" ^ string_of_int (Hashtbl.length c.c_modules) ^ " modules stored)");
-		let rec scan_module_deps m h =
-			if Hashtbl.mem h m.m_id then
-				()
-			else begin
-				Hashtbl.add h m.m_id m;
-				PMap.iter (fun _ m -> scan_module_deps m h) m.m_extra.m_deps
-			end
-		in
-		let all_modules = Hashtbl.fold (fun _ m acc -> PMap.add m.m_id m acc) c.c_modules PMap.empty in
-		let modules = Hashtbl.fold (fun (path,key) m acc ->
-			let mdeps = Hashtbl.create 0 in
-			scan_module_deps m mdeps;
-			let deps = ref [] in
-			let out = ref all_modules in
-			Hashtbl.iter (fun _ md ->
-				out := PMap.remove md.m_id !out;
-				if m == md then () else begin
-				deps := Obj.repr md :: !deps;
-				List.iter (fun t ->
-					match t with
-					| TClassDecl c ->
-						deps := Obj.repr c :: !deps;
-						List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_statics;
-						List.iter (fun f -> deps := Obj.repr f :: !deps) c.cl_ordered_fields;
-					| TEnumDecl e ->
-						deps := Obj.repr e :: !deps;
-						List.iter (fun n -> deps := Obj.repr (PMap.find n e.e_constrs) :: !deps) e.e_names;
-					| TTypeDecl t -> deps := Obj.repr t :: !deps;
-					| TAbstractDecl a -> deps := Obj.repr a :: !deps;
-				) md.m_types;
-				end
-			) mdeps;
-			let chk = Obj.repr Common.memory_marker :: PMap.fold (fun m acc -> Obj.repr m :: acc) !out [] in
-			let inf = Objsize.objsize m !deps chk in
-			(m,Objsize.size_with_headers inf, (inf.Objsize.reached,!deps,!out)) :: acc
-		) c.c_modules [] in
-		let cur_key = ref "" and tcount = ref 0 and mcount = ref 0 in
-		List.iter (fun (m,size,(reached,deps,out)) ->
-			let key = m.m_extra.m_sign in
-			if key <> !cur_key then begin
-				print (Printf.sprintf ("    --- CONFIG %s ----------------------------") (Digest.to_hex key));
-				cur_key := key;
-			end;
-			let sign md =
-				if md.m_extra.m_sign = key then "" else "(" ^ (try Digest.to_hex md.m_extra.m_sign with _ -> "???" ^ md.m_extra.m_sign) ^ ")"
-			in
-			print (Printf.sprintf "    %s : %s" (Ast.s_type_path m.m_path) (fmt_size size));
-			(if reached then try
-				incr mcount;
-				let lcount = ref 0 in
-				let leak l =
-					incr lcount;
-					incr tcount;
-					print (Printf.sprintf "      LEAK %s" l);
-					if !lcount >= 3 && !tcount >= 100 && not verbose then begin
-						print (Printf.sprintf "      ...");
-						raise Exit;
-					end;
-				in
-				if (Objsize.objsize m deps [Obj.repr Common.memory_marker]).Objsize.reached then leak "common";
-				PMap.iter (fun _ md ->
-					if (Objsize.objsize m deps [Obj.repr md]).Objsize.reached then leak (Ast.s_type_path md.m_path ^ sign md);
-				) out;
-			with Exit ->
-				());
-			if verbose then begin
-				print (Printf.sprintf "      %d total deps" (List.length deps));
-				PMap.iter (fun _ md ->
-					print (Printf.sprintf "      dep %s%s" (Ast.s_type_path md.m_path) (sign md));
-				) m.m_extra.m_deps;
-			end;
-			flush stdout
-		) (List.sort (fun (m1,s1,_) (m2,s2,_) ->
-			let k1 = m1.m_extra.m_sign and k2 = m2.m_extra.m_sign in
-			if k1 = k2 then s1 - s2 else if k1 > k2 then 1 else -1
-		) modules);
-		if !mcount > 0 then print ("*** " ^ string_of_int !mcount ^ " modules have leaks !");
-		print "Cache dump complete")
-
 module Initialize = struct
 	let set_platform com pf file =
 		if com.platform <> Cross then failwith "Multiple targets";
@@ -921,7 +664,7 @@ try
 		),"<file>[@name] : add a named resource file");
 		("-prompt", Arg.Unit (fun() -> prompt := true),": prompt on error");
 		("-cmd", Arg.String (fun cmd ->
-			cmds := unquote cmd :: !cmds
+			cmds := DisplayOutput.unquote cmd :: !cmds
 		),": run the specified command after successful compilation");
 		("--flash-strict", define Define.FlashStrict, ": more type strict flash API");
 		("--no-traces", define Define.NoTraces, ": don't compile trace calls in the program");
@@ -945,74 +688,7 @@ try
 		("--next", Arg.Unit (fun() -> assert false), ": separate several haxe compilations");
 		("--each", Arg.Unit (fun() -> assert false), ": append preceding parameters to all haxe compilations separated by --next");
 		("--display", Arg.String (fun file_pos ->
-			match file_pos with
-			| "classes" ->
-				pre_compilation := (fun() -> raise (Parser.TypePath (["."],None,true))) :: !pre_compilation;
-			| "keywords" ->
-				raise (Completion (Display.print_keywords ()))
-			| "memory" ->
-				did_something := true;
-				(try display_memory ctx with e -> prerr_endline (Printexc.get_backtrace ()));
-			| "diagnostics" ->
-				Common.define com Define.NoCOpt;
-				com.display <- DisplayMode.create (DMDiagnostics true);
-				Common.display_default := DMDiagnostics true;
-			| _ ->
-				let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in
-				let file = unquote file in
-				let pos, smode = try ExtString.String.split pos "@" with _ -> pos,"" in
-				let mode = match smode with
-					| "position" ->
-						Common.define com Define.NoCOpt;
-						DMPosition
-					| "usage" ->
-						Common.define com Define.NoCOpt;
-						DMUsage false
-					(*| "rename" ->
-						Common.define com Define.NoCOpt;
-						DMUsage true*)
-					| "package" ->
-						DMPackage
-					| "type" ->
-						Common.define com Define.NoCOpt;
-						DMType
-					| "toplevel" ->
-						Common.define com Define.NoCOpt;
-						DMToplevel
-					| "module-symbols" ->
-						Common.define com Define.NoCOpt;
-						DMModuleSymbols None;
-					| "diagnostics" ->
-						Common.define com Define.NoCOpt;
-						DMDiagnostics false;
-					| "statistics" ->
-						Common.define com Define.NoCOpt;
-						DMStatistics
-					| "signature" ->
-						DMSignature
-					| "" ->
-						DMDefault
-					| _ ->
-						let smode,arg = try ExtString.String.split smode "@" with _ -> pos,"" in
-						match smode with
-							| "resolve" ->
-								DMResolve arg
-							| "workspace-symbols" ->
-								Common.define com Define.NoCOpt;
-								DMModuleSymbols (Some arg)
-							| _ ->
-								DMDefault
-				in
-				let pos = try int_of_string pos with _ -> failwith ("Invalid format : "  ^ pos) in
-				com.display <- DisplayMode.create mode;
-				Common.display_default := mode;
-				Common.define_value com Define.Display (if smode <> "" then smode else "1");
-				Parser.use_doc := true;
-				Parser.resume_display := {
-					Ast.pfile = Path.unique_full_path file;
-					Ast.pmin = pos;
-					Ast.pmax = pos;
-				};
+			DisplayOutput.handle_display_argument com file_pos pre_compilation did_something;
 		),": display code tips");
 		("--no-output", Arg.Unit (fun() -> no_output := true),": compiles but does not generate any file");
 		("--times", Arg.Unit (fun() -> measure_times := true),": measure compilation times");
@@ -1129,7 +805,7 @@ try
 		com.warning <- if com.display.dms_error_policy = EPCollect then (fun s p -> add_diagnostics_message com s p DisplayTypes.DiagnosticsSeverity.Warning) else message ctx;
 		com.error <- error ctx;
 	end;
-	Display.process_display_file com classes;
+	DisplayOutput.process_display_file com classes;
 	let ext = Initialize.initialize_target ctx com classes in
 	(* if we are at the last compilation step, allow all packages accesses - in case of macros or opening another project file *)
 	if com.display.dms_display then begin
@@ -1169,7 +845,7 @@ try
 		com.main <- main;
 		com.types <- types;
 		com.modules <- modules;
-		Display.process_global_display_mode com tctx;
+		DisplayOutput.process_global_display_mode com tctx;
 		Filters.run com tctx main;
 		t();
 		if ctx.has_error then raise Abort;
@@ -1227,7 +903,7 @@ with
 	| Arg.Help msg ->
 		message ctx msg Ast.null_pos
 	| Display.DisplayPackage pack ->
-		raise (Completion (String.concat "." pack))
+		raise (DisplayOutput.Completion (String.concat "." pack))
 	| Display.DisplayFields fields ->
 		let fields = List.map (
 			fun (name,kind,doc) -> name, kind, (Option.default "" doc)
@@ -1235,30 +911,33 @@ with
 		let fields =
 			if !measure_times then begin
 				close_times();
-				(Display.get_timer_fields !start_time) @ fields
+				(DisplayOutput.get_timer_fields !start_time) @ fields
 			end else
 				fields
 		in
-		raise (Completion (Display.print_fields fields))
+		raise (DisplayOutput.Completion (DisplayOutput.print_fields fields))
 	| Display.DisplayType (t,p,doc) ->
-		raise (Completion (Display.print_type t p doc))
-	| Display.DisplaySignatures tl ->
-		raise (Completion (Display.print_signatures tl))
+		raise (DisplayOutput.Completion (DisplayOutput.print_type t p doc))
+	| Display.DisplaySignatures(tl,display_arg) ->
+		if ctx.com.display.dms_kind = DMSignature then
+			raise (DisplayOutput.Completion (DisplayOutput.print_signature tl display_arg))
+		else
+			raise (DisplayOutput.Completion (DisplayOutput.print_signatures tl))
 	| Display.DisplayPosition pl ->
-		raise (Completion (Display.print_positions pl))
+		raise (DisplayOutput.Completion (DisplayOutput.print_positions pl))
 	| Display.DisplayToplevel il ->
-		raise (Completion (Display.print_toplevel il))
+		raise (DisplayOutput.Completion (DisplayOutput.print_toplevel il))
 	| Parser.TypePath (p,c,is_import) ->
 		let fields =
 			match c with
 			| None ->
-				complete_type_path ctx p
+				DisplayOutput.TypePathHandler.complete_type_path com p
 			| Some (c,cur_package) ->
-				complete_type_path_inner ctx p c cur_package is_import
+				DisplayOutput.TypePathHandler.complete_type_path_inner com p c cur_package is_import
 		in
-		Option.may (fun fields -> raise (Completion (Display.print_fields fields))) fields
-	| Display.ModuleSymbols s | Display.Diagnostics s | Display.Statistics s | Display.Metadata s | Display.DisplaySignature s ->
-		raise (Completion s)
+		Option.may (fun fields -> raise (DisplayOutput.Completion (DisplayOutput.print_fields fields))) fields
+	| Display.ModuleSymbols s | Display.Diagnostics s | Display.Statistics s | Display.Metadata s ->
+		raise (DisplayOutput.Completion s)
 	| Interp.Sys_exit i ->
 		ctx.flush();
 		exit i
@@ -1275,7 +954,7 @@ let args = List.tl (Array.to_list Sys.argv) in
 	do_connect host (try int_of_string port with _ -> failwith "Invalid HAXE_COMPILATION_SERVER port") args
 with Not_found -> try
 	process_params create_context args
-with Completion c ->
+with DisplayOutput.Completion c ->
 	prerr_endline c;
 	exit 0
 | Arg.Bad msg ->

+ 1 - 6
src/server.ml

@@ -3,8 +3,7 @@ open Ast
 open Common
 open Common.DisplayMode
 open Type
-
-exception Completion of string
+open DisplayOutput
 
 let measure_times = ref false
 let prompt = ref false
@@ -52,10 +51,6 @@ let create_context params =
 	ctx.flush <- (fun() -> default_flush ctx);
 	ctx
 
-let unquote v =
-	let len = String.length v in
-	if len > 0 && v.[0] = '"' && v.[len - 1] = '"' then String.sub v 1 (len - 2) else v
-
 let parse_hxml_data data =
 	let lines = Str.split (Str.regexp "[\r\n]+") data in
 	List.concat (List.map (fun l ->

+ 29 - 28
src/typing/typeload.ml

@@ -286,7 +286,7 @@ let type_function_arg ctx t e opt p =
 
 let type_var_field ctx t e stat do_display p =
 	if stat then ctx.curfun <- FunStatic else ctx.curfun <- FunMember;
-	let e = if do_display then Display.process_expr ctx.com e else e in
+	let e = if do_display then Display.ExprPreprocessing.process_expr ctx.com e else e in
 	let e = type_expr ctx e (WithType t) in
 	let e = (!cast_or_unify_ref) ctx t e p in
 	match t with
@@ -319,7 +319,7 @@ let rec load_type_def ctx p t =
 			List.find path_matches ctx.m.curmod.m_types
 		with Not_found ->
 			let t,pi = List.find (fun (t2,pi) -> path_matches t2) ctx.m.module_types in
-			Display.mark_import_position ctx.com pi;
+			Display.ImportHandling.mark_import_position ctx.com pi;
 			t
 	with
 		Not_found ->
@@ -347,7 +347,7 @@ let rec load_type_def ctx p t =
 					| (wp,pi) :: l ->
 						try
 							let t = load_type_def ctx p { t with tpackage = wp } in
-							Display.mark_import_position ctx.com pi;
+							Display.ImportHandling.mark_import_position ctx.com pi;
 							t
 						with
 							| Error (Module_not_found _,p2)
@@ -519,7 +519,7 @@ let rec load_instance ?(allow_display=false) ctx (t,pn) allow_no_params p =
 			f params
 		end
 	in
-	if allow_display then Display.check_display_type ctx t pn;
+	if allow_display then Display.DisplayEmitter.check_display_type ctx t pn;
 	t
 
 (*
@@ -1081,7 +1081,7 @@ let type_function_arg_value ctx t c do_display =
 		| None -> None
 		| Some e ->
 			let p = pos e in
-			let e = if do_display then Display.process_expr ctx.com e else e in
+			let e = if do_display then Display.ExprPreprocessing.process_expr ctx.com e else e in
 			let e = ctx.g.do_optimize ctx (type_expr ctx e (WithType t)) in
 			unify ctx e.etype t p;
 			let rec loop e = match e.eexpr with
@@ -1491,7 +1491,7 @@ module Inheritance = struct
 						List.find path_matches ctx.m.curmod.m_types
 					with Not_found ->
 						let t,pi = List.find (fun (lt,_) -> path_matches lt) ctx.m.module_types in
-						Display.mark_import_position ctx.com pi;
+						Display.ImportHandling.mark_import_position ctx.com pi;
 						t
 					in
 					{ t with tpackage = fst (t_path lt) },p
@@ -1563,7 +1563,7 @@ let rec type_type_param ?(enum_constructor=false) ctx path get_params p tp =
 	if enum_constructor then c.cl_meta <- (Meta.EnumConstructorParam,[],null_pos) :: c.cl_meta;
 	let t = TInst (c,List.map snd c.cl_params) in
 	if ctx.is_display_file && Display.is_display_position (pos tp.tp_name) then
-		Display.display_type ctx.com.display t (pos tp.tp_name);
+		Display.DisplayEmitter.display_type ctx.com.display t (pos tp.tp_name);
 	match tp.tp_constraints with
 	| [] ->
 		n, t
@@ -1609,7 +1609,7 @@ let type_function ctx args ret fmode f do_display p =
 		let v,c = add_local ctx n t pn, c in
 		v.v_meta <- m;
 		if do_display && Display.is_display_position pn then
-			Display.display_variable ctx.com.display v pn;
+			Display.DisplayEmitter.display_variable ctx.com.display v pn;
 		if n = "this" then v.v_meta <- (Meta.This,[],null_pos) :: v.v_meta;
 		v,c
 	) args f.f_args in
@@ -1623,15 +1623,15 @@ let type_function ctx args ret fmode f do_display p =
 	let e = if not do_display then
 		type_expr ctx e NoValue
 	else begin
-		let e = Display.process_expr ctx.com e in
+		let e = Display.ExprPreprocessing.process_expr ctx.com e in
 		try
 			if Common.defined ctx.com Define.NoCOpt then raise Exit;
 			type_expr ctx (Optimizer.optimize_completion_expr e) NoValue
 		with
 		| Parser.TypePath (_,None,_) | Exit ->
 			type_expr ctx e NoValue
-		| Display.DisplayType (t,_,_) | Display.DisplaySignatures [(t,_)] when (match follow t with TMono _ -> true | _ -> false) ->
-			type_expr ctx (if ctx.com.display.dms_kind = DMToplevel then Display.find_enclosing ctx.com e else e) NoValue
+		| Display.DisplayType (t,_,_) | Display.DisplaySignatures ([(t,_)],_) when (match follow t with TMono _ -> true | _ -> false) ->
+			type_expr ctx (if ctx.com.display.dms_kind = DMToplevel then Display.ExprPreprocessing.find_enclosing ctx.com e else e) NoValue
 	end in
 	let e = match e.eexpr with
 		| TMeta((Meta.MergeBlock,_,_), ({eexpr = TBlock el} as e1)) -> e1
@@ -2211,7 +2211,7 @@ module ClassInitializer = struct
 
 	let check_field_display ctx p cf =
  		if Display.is_display_position p then
-			Display.display_field ctx.com.display cf p
+			Display.DisplayEmitter.display_field ctx.com.display cf p
 
 	let bind_var (ctx,cctx,fctx) cf e =
 		let c = cctx.tclass in
@@ -2939,33 +2939,34 @@ let add_module ctx m p =
 	Hashtbl.add ctx.g.modules m.m_path m
 
 let handle_path_display ctx path p =
-	match Display.convert_import_to_something_usable !Parser.resume_display path,ctx.com.display.dms_kind with
-		| (Display.IDKPackage sl,_),_ ->
+	let open Display.ImportHandling in
+	match Display.ImportHandling.convert_import_to_something_usable !Parser.resume_display path,ctx.com.display.dms_kind with
+		| (IDKPackage sl,_),_ ->
 			raise (Parser.TypePath(sl,None,true))
-		| (Display.IDKModule(sl,s),_),DMPosition ->
+		| (IDKModule(sl,s),_),DMPosition ->
 			(* We assume that we want to go to the module file, not a specific type
 			   which might not even exist anyway. *)
 			let mt = ctx.g.do_load_module ctx (sl,s) p in
 			let p = { pfile = mt.m_extra.m_file; pmin = 0; pmax = 0} in
 			raise (Display.DisplayPosition [p])
-		| (Display.IDKModule(sl,s),_),_ ->
+		| (IDKModule(sl,s),_),_ ->
 			(* TODO: wait till nadako requests @type display for these, then implement it somehow *)
 			raise (Parser.TypePath(sl,Some(s,false),true))
-		| (Display.IDKSubType(sl,sm,st),p),DMPosition ->
+		| (IDKSubType(sl,sm,st),p),DMPosition ->
 			resolve_position_by_path ctx { tpackage = sl; tname = sm; tparams = []; tsub = Some st} p
-		| (Display.IDKSubType(sl,sm,st),_),_ ->
+		| (IDKSubType(sl,sm,st),_),_ ->
 			raise (Parser.TypePath(sl @ [sm],Some(st,false),true))
-		| ((Display.IDKSubTypeField(sl,sm,st,sf) | Display.IDKModuleField(sl,(sm as st),sf)),p),_ ->
+		| ((IDKSubTypeField(sl,sm,st,sf) | IDKModuleField(sl,(sm as st),sf)),p),_ ->
 			let m = ctx.g.do_load_module ctx (sl,sm) p in
 			List.iter (fun t -> match t with
 				| TClassDecl c when snd c.cl_path = st ->
 					ignore(c.cl_build());
 					let cf = PMap.find sf c.cl_statics in
-					Display.display_field ctx.com.display cf p
+					Display.DisplayEmitter.display_field ctx.com.display cf p
 				| _ ->
 					()
 			) m.m_types;
-		| (Display.IDK,_),_ ->
+		| (IDK,_),_ ->
 			()
 
 (*
@@ -2980,9 +2981,9 @@ let init_module_type ctx context_init do_init (decl,p) =
 	let check_path_display path p = match ctx.com.display.dms_kind with
 		(* We cannot use ctx.is_display_file because the import could come from an import.hx file. *)
 		| DMDiagnostics b when (b && not (ExtString.String.ends_with p.pfile "import.hx")) || Display.is_display_file p.pfile ->
-			Display.add_import_position ctx.com p path;
+			Display.ImportHandling.add_import_position ctx.com p path;
 		| DMStatistics | DMUsage _ ->
-			Display.add_import_position ctx.com p path;
+			Display.ImportHandling.add_import_position ctx.com p path;
 		| _ ->
 			if Display.is_display_file p.pfile then handle_path_display ctx path p
 	in
@@ -3143,7 +3144,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 	| EClass d ->
 		let c = (match get_type (fst d.d_name) with TClassDecl c -> c | _ -> assert false) in
 		if ctx.is_display_file && Display.is_display_position (pos d.d_name) then
-			Display.display_module_type ctx.com.display (match c.cl_kind with KAbstractImpl a -> TAbstractDecl a | _ -> TClassDecl c) (pos d.d_name);
+			Display.DisplayEmitter.display_module_type ctx.com.display (match c.cl_kind with KAbstractImpl a -> TAbstractDecl a | _ -> TClassDecl c) (pos d.d_name);
 		check_global_metadata ctx c.cl_meta (fun m -> c.cl_meta <- m :: c.cl_meta) c.cl_module.m_path c.cl_path None;
 		let herits = d.d_flags in
 		c.cl_extern <- List.mem HExtern herits;
@@ -3198,7 +3199,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 	| EEnum d ->
 		let e = (match get_type (fst d.d_name) with TEnumDecl e -> e | _ -> assert false) in
 		if ctx.is_display_file && Display.is_display_position (pos d.d_name) then
-			Display.display_module_type ctx.com.display (TEnumDecl e) (pos d.d_name);
+			Display.DisplayEmitter.display_module_type ctx.com.display (TEnumDecl e) (pos d.d_name);
 		let ctx = { ctx with type_params = e.e_params } in
 		let h = (try Some (Hashtbl.find ctx.g.type_patches e.e_path) with Not_found -> None) in
 		check_global_metadata ctx e.e_meta (fun m -> e.e_meta <- m :: e.e_meta) e.e_module.m_path e.e_path None;
@@ -3309,7 +3310,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 				cf_overloads = [];
 			} in
  			if ctx.is_display_file && Display.is_display_position p then
- 				Display.display_enum_field ctx.com.display f p;
+ 				Display.DisplayEmitter.display_enum_field ctx.com.display f p;
 			e.e_constrs <- PMap.add f.ef_name f e.e_constrs;
 			fields := PMap.add cf.cf_name cf !fields;
 			incr index;
@@ -3336,7 +3337,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 	| ETypedef d ->
 		let t = (match get_type (fst d.d_name) with TTypeDecl t -> t | _ -> assert false) in
 		if ctx.is_display_file && Display.is_display_position (pos d.d_name) then
-			Display.display_module_type ctx.com.display (TTypeDecl t) (pos d.d_name);
+			Display.DisplayEmitter.display_module_type ctx.com.display (TTypeDecl t) (pos d.d_name);
 		check_global_metadata ctx t.t_meta (fun m -> t.t_meta <- m :: t.t_meta) t.t_module.m_path t.t_path None;
 		let ctx = { ctx with type_params = t.t_params } in
 		let tt = load_complex_type ctx true p d.d_data in
@@ -3374,7 +3375,7 @@ let init_module_type ctx context_init do_init (decl,p) =
 	| EAbstract d ->
 		let a = (match get_type (fst d.d_name) with TAbstractDecl a -> a | _ -> assert false) in
 		if ctx.is_display_file && Display.is_display_position (pos d.d_name) then
-			Display.display_module_type ctx.com.display (TAbstractDecl a) (pos d.d_name);
+			Display.DisplayEmitter.display_module_type ctx.com.display (TAbstractDecl a) (pos d.d_name);
 		check_global_metadata ctx a.a_meta (fun m -> a.a_meta <- m :: a.a_meta) a.a_module.m_path a.a_path None;
 		let ctx = { ctx with type_params = a.a_params } in
 		let is_type = ref false in

+ 15 - 17
src/typing/typer.ml

@@ -1179,7 +1179,7 @@ let rec using_field ctx mode e i p =
 						| _ -> ()
 					) monos cf.cf_params;
 					let et = type_module_type ctx (TClassDecl c) None p in
-					Display.maybe_mark_import_position ctx pc;
+					Display.ImportHandling.maybe_mark_import_position ctx pc;
 					AKUsing (mk (TField (et,FStatic (c,cf))) t p,c,cf,e)
 				| _ ->
 					raise Not_found
@@ -1302,7 +1302,7 @@ let rec type_ident_raise ctx i p mode =
 							let et = type_module_type ctx (TClassDecl c) None p in
 							let fa = FStatic(c,cf) in
 							let t = monomorphs cf.cf_params cf.cf_type in
-							Display.maybe_mark_import_position ctx pt;
+							Display.ImportHandling.maybe_mark_import_position ctx pt;
 							begin match cf.cf_kind with
 								| Var {v_read = AccInline} -> AKInline(et,cf,fa,t)
 								| _ -> AKExpr (mk (TField(et,fa)) t p)
@@ -1323,7 +1323,7 @@ let rec type_ident_raise ctx i p mode =
 						let et = type_module_type ctx t None p in
 						let monos = List.map (fun _ -> mk_mono()) e.e_params in
 						let monos2 = List.map (fun _ -> mk_mono()) ef.ef_params in
-						Display.maybe_mark_import_position ctx pt;
+						Display.ImportHandling.maybe_mark_import_position ctx pt;
 						wrap (mk (TField (et,FEnum (e,ef))) (enum_field_type ctx e ef monos monos2 p) p)
 					with
 						Not_found -> loop l
@@ -1332,7 +1332,7 @@ let rec type_ident_raise ctx i p mode =
 	with Not_found ->
 		(* lookup imported globals *)
 		let t, name, pi = PMap.find i ctx.m.module_globals in
-		Display.maybe_mark_import_position ctx pi;
+		Display.ImportHandling.maybe_mark_import_position ctx pi;
 		let e = type_module_type ctx t None p in
 		type_field ctx e name p mode
 
@@ -2604,7 +2604,7 @@ and handle_efield ctx e p mode =
 								List.find path_match ctx.m.curmod.m_types
 							with Not_found ->
 								let t,p = List.find (fun (t,_) -> path_match t) ctx.m.module_types in
-								Display.maybe_mark_import_position ctx p;
+								Display.ImportHandling.maybe_mark_import_position ctx p;
 								t
 							in
 							(* if the static is not found, look for a subtype instead - #1916 *)
@@ -2732,7 +2732,7 @@ and type_vars ctx vl p =
 			let v = add_local ctx v t pv in
 			v.v_meta <- (Meta.UserVariable,[],pv) :: v.v_meta;
 			if ctx.in_display && Display.is_display_position pv then
-				Display.display_variable ctx.com.display v pv;
+				Display.DisplayEmitter.display_variable ctx.com.display v pv;
 			v,e
 		with
 			Error (e,p) ->
@@ -2753,7 +2753,7 @@ and format_string ctx s p =
 	let add_expr (enext,p) len =
 		min := !min + len;
 		let enext = if ctx.in_display && Display.is_display_position p then
-			Display.process_expr ctx.com (enext,p)
+			Display.ExprPreprocessing.process_expr ctx.com (enext,p)
 		else
 			enext,p
 		in
@@ -3040,7 +3040,7 @@ and type_new ctx path el with_type p =
 		| mt ->
 			error ((s_type_path (t_infos mt).mt_path) ^ " cannot be constructed") p
 	in
-	Display.check_display_type ctx t (pos path);
+	Display.DisplayEmitter.check_display_type ctx t (pos path);
 	let build_constructor_call c tl =
 		let ct, f = get_constructor ctx c tl p in
 		if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
@@ -3138,7 +3138,7 @@ and type_try ctx e1 catches with_type p =
 		let locals = save_locals ctx in
 		let v = add_local ctx v t pv in
 		if ctx.is_display_file && Display.is_display_position pv then
-			Display.display_variable ctx.com.display v pv;
+			Display.DisplayEmitter.display_variable ctx.com.display v pv;
 		let e = type_expr ctx e_ast with_type in
 		(* If the catch position is the display position it means we get completion on the catch keyword or some
 		   punctuation. Otherwise we wouldn't reach this point. *)
@@ -3607,13 +3607,14 @@ and type_expr ctx (e,p) (with_type:with_type) =
 		if iscall then handle_signature_display ctx e with_type
 		else handle_display ctx e with_type
 	| EDisplayNew t ->
-		let t = Typeload.load_instance ctx t true p in
+		assert false
+		(*let t = Typeload.load_instance ctx t true p in
 		(match follow t with
 		| TInst (c,params) | TAbstract({a_impl = Some c},params) ->
 			let ct, f = get_constructor ctx c params p in
 			raise (Display.DisplaySignatures ((ct,f.cf_doc) :: List.map (fun f -> (f.cf_type,f.cf_doc)) f.cf_overloads))
 		| _ ->
-			error "Not a class" p)
+			error "Not a class" p)*)
 	| ECheckType (e,t) ->
 		let t = Typeload.load_complex_type ctx true p t in
 		let e = type_expr ctx e (WithType t) in
@@ -3679,9 +3680,9 @@ and handle_display ctx e_ast with_type =
 	let e = match e_ast,with_type with
 	| (EConst (Ident "$type"),_),_ ->
 		let mono = mk_mono() in
-		raise (Display.DisplaySignatures [(TFun(["expression",false,mono],mono),Some "Outputs type of argument as a warning and uses argument as value")])
+		raise (Display.DisplaySignatures ([(TFun(["expression",false,mono],mono),Some "Outputs type of argument as a warning and uses argument as value")],0))
 	| (EConst (Ident "trace"),_),_ ->
-		raise (Display.DisplaySignatures [(tfun [t_dynamic] ctx.com.basic.tvoid,Some "Print given arguments")])
+		raise (Display.DisplaySignatures ([(tfun [t_dynamic] ctx.com.basic.tvoid,Some "Print given arguments")],0))
 	| (EConst (Ident "_"),p),WithType t ->
 		mk (TConst TNull) t p (* This is "probably" a bind skip, let's just use the expected type *)
 	| _ -> try
@@ -3772,10 +3773,7 @@ and handle_signature_display ctx e_ast with_type =
 			acc
 	in
 	let overloads = match loop [] tl with [] -> tl | tl -> tl in
-	if ctx.com.display.dms_kind = DMSignature then
-		raise (Display.DisplaySignature (Display.display_signature overloads display_arg))
-	else
-		raise (Display.DisplaySignatures overloads)
+	raise (Display.DisplaySignatures(overloads,display_arg))
 
 and display_expr ctx e_ast e with_type p =
 	let get_super_constructor () = match ctx.curclass.cl_super with