Skip to content

Commit

Permalink
[#22] Move functions to poi module, refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
robertoaloi committed Aug 5, 2019
1 parent 0a9d9ba commit 5f3bdd4
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 112 deletions.
2 changes: 1 addition & 1 deletion src/erlang_ls_buffer.erl
Expand Up @@ -140,7 +140,7 @@ do_get_mfa(Text, Line, _Character) ->
{M, F, A}.

-spec do_get_element_at_pos(binary(), non_neg_integer(), non_neg_integer()) ->
[erlang_ls_parser:poi()].
[erlang_ls_poi:poi()].
do_get_element_at_pos(Text, Line, Column) ->
%% TODO: Cache tree
{ok, Tree} = erlang_ls_parser:parse(Text),
Expand Down
95 changes: 11 additions & 84 deletions src/erlang_ls_parser.erl
Expand Up @@ -8,29 +8,19 @@
, parse_file/1
]).

-type line() :: non_neg_integer().
-type column() :: non_neg_integer().
-type pos() :: {line(), column()}.
-type range() :: #{ from := pos(), to := pos() }.
%% Point of Interest
-type poi() :: #{ type := atom(), info => any(), range := range()}.

-export_type([ poi/0
, range/0
]).

%% TODO: Generate random filename
%% TODO: Ideally avoid writing to file at all (require epp changes)
-define(TMP_PATH, <<"/tmp/erlang_ls_tmp">>).

-spec parse(binary()) -> {ok, syntax_tree()}.
-spec parse(binary()) -> {ok, erlang_ls_tree:tree()}.
parse(Text) ->
%% epp_dodger only works with source files,
%% so let's use a temporary file.
ok = file:write_file(?TMP_PATH, Text),
parse_file(?TMP_PATH).

-spec parse_file(binary()) -> {ok, syntax_tree()} | {error, any()}.
-spec parse_file(binary()) ->
{ok, erlang_ls_tree:tree()} | {error, any()}.
parse_file(Path) ->
case file:open(Path, [read]) of
{ok, IoDevice} ->
Expand All @@ -47,77 +37,23 @@ parse_file(Path) ->
{error, Error}
end.

-spec get_range(syntax_tree(), pos(), {atom(), any()}) -> range().
get_range({Line, Column}, {application, {M, F, _A}}) ->
CFrom = Column - length(atom_to_list(M)),
From = {Line, CFrom},
CTo = Column + length(atom_to_list(F)),
To = {Line, CTo},
#{ from => From, to => To };
get_range({Line, Column}, {application, {F, _A}}) ->
From = {Line, Column},
To = {Line, Column + length(atom_to_list(F))},
#{ from => From, to => To };
get_range({Line, Column}, {behaviour, Behaviour}) ->
From = {Line, Column - 1},
To = {Line, Column + length("behaviour") + length(atom_to_list(Behaviour))},
#{ from => From, to => To };
get_range({_Line, _Column}, {exports_entry, {_F, _A}}) ->
%% TODO: The location information for the arity qualifiers are lost during
%% parsing in `epp_dodger`. This requires fixing.
#{ from => {0, 0}, to => {0, 0} };
get_range({Line, Column}, {function, {F, _A}}) ->
From = {Line - 1, Column - 1},
To = {Line - 1, Column + length(atom_to_list(F)) - 1},
#{ from => From, to => To };
get_range({Line, _Column}, {define, _Define}) ->
From = {Line - 1, 0},
To = From,
#{ from => From, to => To };
get_range({Line, Column}, {include, Include}) ->
From = {Line, Column - 1},
To = {Line, Column + length("include") + length(Include)},
#{ from => From, to => To };
get_range({Line, Column}, {include_lib, Include}) ->
From = {Line, Column - 1},
To = {Line, Column + length("include_lib") + length(Include)},
#{ from => From, to => To };
get_range({Line, Column}, {macro, Macro}) ->
From = {Line, Column},
To = {Line, Column + length(atom_to_list(Macro))},
#{ from => From, to => To };
get_range({Line, Column}, {module, _}) ->
From = {Line - 1, Column - 1},
To = From,
#{ from => From, to => To };
get_range({Line, Column}, {record_expr, Record}) ->
From = {Line, Column - 1},
To = {Line, Column + length(Record) - 1},
#{ from => From, to => To };
%% TODO: Distinguish between usage poi and definition poi
get_range({Line, _Column}, {record, _Record}) ->
From = {Line - 1, 0},
To = From,
#{ from => From, to => To };
get_range({_Line, _Column}, {spec, _Spec}) ->
%% TODO: The location information for the arity qualifiers are lost during
%% parsing in `epp_dodger`. This requires fixing.
#{ from => {0, 0}, to => {0, 0} }.

-spec find_poi_by_info(syntax_tree(), any()) -> [poi()].
-spec find_poi_by_info(erlang_ls_tree:tree(), any()) ->
[erlang_ls_poi:poi()].
find_poi_by_info(Tree, Info0) ->
[POI || #{info := Info} = POI <- list_poi(Tree), Info0 =:= Info].

%% TODO: Rename
-spec find_poi_by_info_key(syntax_tree(), atom()) -> [poi()].
-spec find_poi_by_info_key(erlang_ls_tree:tree(), atom()) ->
[erlang_ls_poi:poi()].
find_poi_by_info_key(Tree, Key0) ->
[POI || #{info := {Key, _}} = POI <- list_poi(Tree), Key0 =:= Key].

-spec find_poi_by_pos(syntax_tree(), pos()) -> [poi()].
-spec find_poi_by_pos(erlang_ls_tree:tree(), erlang_ls_poi:pos()) ->
[erlang_ls_poi:poi()].
find_poi_by_pos(Tree, Pos) ->
[POI || #{range := Range} = POI <- list_poi(Tree), matches_pos(Pos, Range)].

-spec list_poi(syntax_tree()) -> [poi()].
-spec list_poi(erlang_ls_tree:tree()) -> [erlang_ls_poi:poi()].
list_poi(Tree) ->
F = fun(T, Acc) ->
Annotations = erl_syntax:get_ann(T),
Expand All @@ -128,15 +64,6 @@ list_poi(Tree) ->
end,
erl_syntax_lib:fold(F, [], Tree).

-spec matches_pos(pos(), range()) -> boolean().
-spec matches_pos(erlang_ls_poi:pos(), erlang_ls_poi:range()) -> boolean().
matches_pos(Pos, #{from := From, to := To}) ->
(From =< Pos) andalso (Pos =< To).

-spec poi(syntax_tree(), any()) -> poi().
poi(Tree, Info) ->
Pos = erl_syntax:get_pos(Tree),
Range = get_range(Pos, Info),
#{ type => poi
, info => Info
, range => Range
}.
92 changes: 92 additions & 0 deletions src/erlang_ls_poi.erl
@@ -0,0 +1,92 @@
%%==============================================================================
%% The Point Of Interest (a.k.a. _poi_) Data Structure
%%==============================================================================
-module(erlang_ls_poi).

-type line() :: non_neg_integer().
-type column() :: non_neg_integer().
-type pos() :: {line(), column()}.
-type range() :: #{ from := pos(), to := pos() }.
-type poi() :: #{ type := atom()
, info => any()
, range := range()
}.

-export_type([ poi/0
, pos/0
, range/0
]).


-export([ poi/2 ]).

%% @edoc Constructor for a Point of Interest.
-spec poi(erlang_ls_tree:tree(), any()) -> poi().
poi(Tree, Info) ->
Pos = erl_syntax:get_pos(Tree),
Range = get_range(Pos, Info),
#{ type => poi
, info => Info
, range => Range
}.

%%==============================================================================
%% Internal Functions
%%==============================================================================

-spec get_range(pos(), {atom(), any()}) -> range().
get_range({Line, Column}, {application, {M, F, _A}}) ->
CFrom = Column - length(atom_to_list(M)),
From = {Line, CFrom},
CTo = Column + length(atom_to_list(F)),
To = {Line, CTo},
#{ from => From, to => To };
get_range({Line, Column}, {application, {F, _A}}) ->
From = {Line, Column},
To = {Line, Column + length(atom_to_list(F))},
#{ from => From, to => To };
get_range({Line, Column}, {behaviour, Behaviour}) ->
From = {Line, Column - 1},
To = {Line, Column + length("behaviour") + length(atom_to_list(Behaviour))},
#{ from => From, to => To };
get_range({_Line, _Column}, {exports_entry, {_F, _A}}) ->
%% TODO: The location information for the arity qualifiers are lost during
%% parsing in `epp_dodger`. This requires fixing.
#{ from => {0, 0}, to => {0, 0} };
get_range({Line, Column}, {function, {F, _A}}) ->
From = {Line - 1, Column - 1},
To = {Line - 1, Column + length(atom_to_list(F)) - 1},
#{ from => From, to => To };
get_range({Line, _Column}, {define, _Define}) ->
From = {Line - 1, 0},
To = From,
#{ from => From, to => To };
get_range({Line, Column}, {include, Include}) ->
From = {Line, Column - 1},
To = {Line, Column + length("include") + length(Include)},
#{ from => From, to => To };
get_range({Line, Column}, {include_lib, Include}) ->
From = {Line, Column - 1},
To = {Line, Column + length("include_lib") + length(Include)},
#{ from => From, to => To };
get_range({Line, Column}, {macro, Macro}) ->
From = {Line, Column},
To = {Line, Column + length(atom_to_list(Macro))},
#{ from => From, to => To };
get_range({Line, Column}, {module, _}) ->
From = {Line - 1, Column - 1},
To = From,
#{ from => From, to => To };
get_range({Line, Column}, {record_expr, Record}) ->
From = {Line, Column - 1},
To = {Line, Column + length(Record) - 1},
#{ from => From, to => To };
%% TODO: Distinguish between usage poi and definition poi
get_range({Line, _Column}, {record, _Record}) ->
From = {Line - 1, 0},
To = From,
#{ from => From, to => To };
get_range({_Line, _Column}, {spec, _Spec}) ->
%% TODO: The location information for the arity qualifiers are lost during
%% parsing in `epp_dodger`. This requires fixing.
#{ from => {0, 0}, to => {0, 0} }.
2 changes: 1 addition & 1 deletion src/erlang_ls_protocol.erl
Expand Up @@ -52,7 +52,7 @@ response(RequestId, Result) ->
%%==============================================================================
%% Data Structures
%%==============================================================================
-spec range(erlang_ls_parser:range()) -> range().
-spec range(erlang_ls_poi:range()) -> range().
range(#{ from := {FromL, FromC}, to := {ToL, ToC} }) ->
#{ start => #{line => FromL, character => FromC}
, 'end' => #{line => ToL, character => ToC}
Expand Down
12 changes: 6 additions & 6 deletions src/erlang_ls_server.erl
Expand Up @@ -208,7 +208,7 @@ send_notification(Socket, Method, Params) ->
gen_tcp:send(Socket, Notification).

%% TODO: definition/2 should probably not take the Uri, but a path.
-spec definition(uri(), erlang_ls_parser:poi()) -> null | map().
-spec definition(uri(), erlang_ls_poi:poi()) -> null | map().
definition(_Uri, #{ info := {application, {M, _F, _A}} = Info }) ->
case annotated_tree(erlang_ls_uri:filename(M)) of
{ok, Uri, AnnotatedTree} ->
Expand Down Expand Up @@ -291,20 +291,20 @@ definition({record_expr, Record}) ->
{record, Record}.

-spec annotated_tree(binary()) ->
{ok, uri(), erlang_ls_parser:syntax_tree()} | {error, any()}.
{ok, uri(), erlang_ls_tree:tree()} | {error, any()}.
annotated_tree(Filename) ->
annotated_tree(Filename, full_path()).

-spec annotated_tree(binary(), [string()]) ->
{ok, uri(), erlang_ls_parser:syntax_tree()} | {error, any()}.
{ok, uri(), erlang_ls_tree:tree()} | {error, any()}.
annotated_tree(Filename, Path) ->
case file:path_open(Path, Filename, [read]) of
{ok, IoDevice, FullName} ->
%% TODO: Avoid opening file twice
file:close(IoDevice),
{ok, Tree} = erlang_ls_parser:parse_file(FullName),
Uri = erlang_ls_uri:uri(FullName),
{ok, Uri, erlang_ls_parser:annotate(Tree)};
{ok, Uri, erlang_ls_tree:annotate(Tree)};
{error, Error} ->
{error, Error}
end.
Expand Down Expand Up @@ -346,7 +346,7 @@ search(Filename, Path, Thing) ->
end.

%% Look for a definition in a given tree
-spec find(uri(), erlang_ls_parser:syntax_tree(), any()) -> null | map().
-spec find(uri(), erlang_ls_tree:tree(), any()) -> null | map().
find(Uri, AnnotatedTree, Thing) ->
case erlang_ls_parser:find_poi_by_info(AnnotatedTree, Thing) of
[#{ range := Range }|_] ->
Expand All @@ -355,7 +355,7 @@ find(Uri, AnnotatedTree, Thing) ->
null
end.

-spec search_in_includes([erlang_ls_parser:poi()], string()) -> null | map().
-spec search_in_includes([erlang_ls_poi:poi()], string()) -> null | map().
search_in_includes([], _Thing) ->
null;
search_in_includes([#{info := Info}|T], Thing) ->
Expand Down

0 comments on commit 5f3bdd4

Please sign in to comment.