Skip to content

Commit

Permalink
add toplevel completion, resolve positions for position/usage complet…
Browse files Browse the repository at this point in the history
…ion (closes #327, closes #569)
  • Loading branch information
Simn committed May 12, 2014
1 parent f6bb541 commit 8eed508
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 56 deletions.
4 changes: 3 additions & 1 deletion codegen.ml
Expand Up @@ -925,6 +925,8 @@ let detect_usage com =
Type.iter expr e
| TLocal v when Meta.has Meta.Usage v.v_meta ->
usage := e.epos :: !usage
| TVar (v,_) when com.display = DMPosition && Meta.has Meta.Usage v.v_meta ->
raise (Typecore.DisplayPosition [e.epos])
| _ -> Type.iter expr e
in
let field cf = match cf.cf_expr with None -> () | Some e -> expr e in
Expand Down Expand Up @@ -1710,4 +1712,4 @@ module DeprecationCheck = struct
| _ ->
()
) com.types
end
end
2 changes: 1 addition & 1 deletion common.ml
Expand Up @@ -104,8 +104,8 @@ type display_mode =
| DMNone
| DMDefault
| DMUsage
| DMMetadata
| DMPosition
| DMToplevel

type context = {
(* config *)
Expand Down
9 changes: 6 additions & 3 deletions filters.ml
Expand Up @@ -1079,11 +1079,14 @@ let post_process_end() =
incr pp_counter

let run com tctx main =
if com.display = DMUsage then
Codegen.detect_usage com;
begin match com.display with
| DMUsage | DMPosition ->
Codegen.detect_usage com;
| _ ->
()
end;
if not (Common.defined com Define.NoDeprecationWarnings) then
Codegen.DeprecationCheck.run com;

(* PASS 1: general expression filters *)
let filters = [
Codegen.UnificationCallback.run (check_unification com);
Expand Down
59 changes: 39 additions & 20 deletions main.ml
Expand Up @@ -1139,17 +1139,24 @@ try
| _ ->
let file, pos = try ExtString.String.split file_pos "@" with _ -> failwith ("Invalid format : " ^ file_pos) in
let file = unquote file in
let pos, mode = try ExtString.String.split pos "@" with _ -> pos,"" in
let mode = match mode with
| "position" -> DMPosition
| "usage" -> DMUsage
| "metadata" -> DMMetadata
| _ -> DMDefault
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
| "toplevel" ->
Common.define com Define.NoCOpt;
DMToplevel
| _ ->
DMDefault
in
let pos = try int_of_string pos with _ -> failwith ("Invalid format : " ^ pos) in
com.display <- mode;
Common.display_default := mode;
Common.define com Define.Display;
Common.define_value com Define.Display (if smode <> "" then smode else "1");
Parser.use_doc := true;
Parser.resume_display := {
Ast.pfile = Common.unique_full_path file;
Expand Down Expand Up @@ -1360,7 +1367,12 @@ try
"python"
) 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 <> DMNone && not ctx.has_next then com.package_rules <- PMap.foldi (fun p r acc -> match r with Forbidden -> acc | _ -> PMap.add p r acc) com.package_rules PMap.empty;
begin match com.display with
| DMNone | DMToplevel ->
()
| _ ->
if not ctx.has_next then com.package_rules <- PMap.foldi (fun p r acc -> match r with Forbidden -> acc | _ -> PMap.add p r acc) com.package_rules PMap.empty;
end;
com.config <- get_config com; (* make sure to adapt all flags changes defined after platform *)

(* check file extension. In case of wrong commandline, we don't want
Expand Down Expand Up @@ -1389,7 +1401,7 @@ try
t();
if ctx.has_error then raise Abort;
begin match com.display with
| DMNone | DMUsage ->
| DMNone | DMUsage | DMPosition ->
()
| _ ->
if ctx.has_next then raise Abort;
Expand Down Expand Up @@ -1522,23 +1534,30 @@ with
| Typecore.DisplayPosition pl ->
let b = Buffer.create 0 in
let error_printer file line = sprintf "%s:%d:" (Common.unique_full_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>\n";
Buffer.add_string b "<pos>";
Buffer.add_string b epos;
Buffer.add_string b "\n</pos>\n";
Buffer.add_string b "</pos>\n";
) pl;
Buffer.add_string b "</list>";
raise (Completion (Buffer.contents b))
| Typer.DisplayMetadata m ->
| Typer.DisplayToplevel il ->
let b = Buffer.create 0 in
List.iter (fun (m,el,p) ->
Buffer.add_string b ("<meta name=\"" ^ (fst (MetaInfo.to_string m)) ^ "\"");
if el = [] then Buffer.add_string b "/>" else begin
Buffer.add_string b ">\n";
List.iter (fun e -> Buffer.add_string b ((htmlescape (Ast.s_expr e)) ^ "\n")) el;
Buffer.add_string b "</meta>\n";
end
) m;
Buffer.add_string b "<il>\n";
let ctx = print_context() in
let s_type t = htmlescape (s_type ctx t) in
List.iter (fun id -> match id with
| Typer.ITLocal v -> Buffer.add_string b (Printf.sprintf "<i k=\"local\" t=\"%s\">%s</i>\n" (s_type v.v_type) v.v_name);
| Typer.ITMember(c,cf) -> Buffer.add_string b (Printf.sprintf "<i k=\"member\" t=\"%s\">%s</i>\n" (s_type cf.cf_type) cf.cf_name);
| Typer.ITStatic(c,cf) -> Buffer.add_string b (Printf.sprintf "<i k=\"static\" t=\"%s\">%s</i>\n" (s_type cf.cf_type) cf.cf_name);
| Typer.ITEnum(en,ef) -> Buffer.add_string b (Printf.sprintf "<i k=\"enum\" t=\"%s\">%s</i>\n" (s_type ef.ef_type) ef.ef_name);
| Typer.ITGlobal(mt,s,t) -> Buffer.add_string b (Printf.sprintf "<i k=\"global\" p=\"%s\" t=\"%s\">%s</i>\n" (s_type_path (t_infos mt).mt_path) (s_type t) s);
| Typer.ITType(mt) -> Buffer.add_string b (Printf.sprintf "<i k=\"type\" p=\"%s\">%s</i>\n" (s_type_path (t_infos mt).mt_path) (snd (t_infos mt).mt_path));
| Typer.ITPackage s -> Buffer.add_string b (Printf.sprintf "<i k=\"package\">%s<i>\n" s)
) il;
Buffer.add_string b "</il>";
raise (Completion (Buffer.contents b))
| Parser.TypePath (p,c) ->
(match c with
Expand Down
8 changes: 6 additions & 2 deletions std/haxe/macro/Compiler.hx
Expand Up @@ -106,11 +106,15 @@ class Compiler {
} else {
function(c) return Lambda.has(ignore, c);
}
var displayValue = Context.definedValue("display");
if( classPaths == null ) {
classPaths = Context.getClassPath();
// do not force inclusion when using completion
if( Context.defined("display") )
return;
switch (displayValue) {
case null:
case "usage":
case _: return;
}
// normalize class path
for( i in 0...classPaths.length ) {
var cp = StringTools.replace(classPaths[i], "\\", "/");
Expand Down
1 change: 1 addition & 0 deletions std/haxe/rtti/CType.hx
Expand Up @@ -26,6 +26,7 @@ typedef Path = String
typedef Platforms = List<String>

typedef FunctionArgument = { name : String, opt : Bool, t : CType, ?value:String }

enum CType {
CUnknown;
CEnum( name : Path, params : List<CType> );
Expand Down
85 changes: 77 additions & 8 deletions typeload.ml
Expand Up @@ -1171,6 +1171,67 @@ let type_function_params ctx fd fname p =
) fd.f_params;
!params

let find_enclosing com e =
let display_pos = ref (!Parser.resume_display) in
let encloses_display_pos p =
if p.pmin <= !display_pos.pmin && p.pmax >= !display_pos.pmax 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(e,false)),p in
(true,e_d :: el)
end
) (false,[]) el in
let el = if b then
el
else begin
(EDisplay(((EConst(Ident "null")),p),false),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.pmax = !display_pos.pmin - 1 then begin
display_pos := { pfile = ""; pmin = -2; pmax = -2 };
true
end else
false
in
let rec 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 type_function ctx args ret fmode f do_display p =
let locals = save_locals ctx in
let fargs = List.map (fun (n,c,t) ->
Expand Down Expand Up @@ -1199,15 +1260,23 @@ let type_function ctx args ret fmode f do_display p =
ctx.ret <- ret;
ctx.opened <- [];
let e = match f.f_expr with None -> error "Function body required" p | Some e -> e in
let e = if not do_display then type_expr ctx e NoValue else 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 ->
let e = if not do_display then
type_expr ctx e NoValue
| DisplayTypes [t] when (match follow t with TMono _ -> true | _ -> false) ->
type_expr ctx e NoValue
in
else begin
let e = match ctx.com.display with
| DMToplevel -> find_enclosing ctx.com e
| DMPosition | DMUsage -> find_before_pos ctx.com e
| _ -> 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
| DisplayTypes [t] when (match follow t with TMono _ -> true | _ -> false) ->
type_expr ctx (if ctx.com.display = DMToplevel then 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
| _ -> e
Expand Down

1 comment on commit 8eed508

@Simn
Copy link
Member Author

@Simn Simn commented on 8eed508 May 12, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See clemos/haxe-sublime-bundle#129 (comment)

I'll document this properly once it's a bit more stable.

Please sign in to comment.