Skip to content

Commit

Permalink
Merge pull request #45 from inaka/jfacorro.14.improvements
Browse files Browse the repository at this point in the history
[#14] Modified AST node generation for 'case' and list comprehension
  • Loading branch information
elbrujohalcon committed Jul 18, 2014
2 parents c94464d + 9a662c6 commit 806b463
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 9 deletions.
38 changes: 34 additions & 4 deletions src/elvis_code.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

-export([
parse_tree/1,
past_nesting_limit/2
past_nesting_limit/2,
print_node/1,
print_node/2
]).

-export([
Expand Down Expand Up @@ -75,6 +77,18 @@ past_nesting_limit(#{content := Content},
past_nesting_limit(_Node, _CurrentLeve, _MaxLevel) ->
[].

%% @doc Debugging utility function.
-spec print_node(tree_node()) -> ok.
print_node(Node) ->
print_node(Node, 0).

-spec print_node(tree_node(), integer()) -> ok.
print_node(Node = #{type := Type}, CurrentLevel) ->
Indentation = lists:duplicate(CurrentLevel * 4, 32),
{Line, _} = elvis_code:attr(location, Node),
lager:info("~s - [~p] ~p : ~p~n",
[Indentation, CurrentLevel, Type, Line]).

%% @private
%% @doc Takes a node type and determines its nesting level increment.
level_increment(Type) ->
Expand Down Expand Up @@ -206,9 +220,19 @@ to_map({remote, Location, Module, Function}) ->
%% case

to_map({'case', Location, Expr, Clauses}) ->
CaseExpr = to_map({case_expr, Location, Expr}),
CaseClauses = to_map({case_clauses, Location, Clauses}),
#{type => 'case',
attrs => #{location => Location,
expression => to_map(Expr)},
content => [CaseExpr, CaseClauses]};
to_map({case_expr, Location, Expr}) ->
#{type => case_expr,
attrs => #{location => Location},
content => [to_map(Expr)]};
to_map({case_clauses, Location, Clauses}) ->
#{type => case_clauses,
attrs => #{location => Location},
content => to_map(Clauses)};

%% fun
Expand Down Expand Up @@ -359,15 +383,21 @@ to_map({Type, Location, Key, Value}) when
%% List Comprehension

to_map({lc, Location, Expr, GeneratorsFilters}) ->
LcExpr = to_map({lc_expr, Location, Expr}),
LcGenerators = to_map(GeneratorsFilters),
#{type => lc,
attrs => #{location => Location,
expression => to_map(Expr)},
content => to_map(GeneratorsFilters)};
attrs => #{location => Location},
content => [LcExpr | LcGenerators]};

to_map({generate, Location, Pattern, Expr}) ->
#{type => generate,
attrs => #{location => Location,
pattern => to_map(Pattern),
expression => to_map(Expr)}};
to_map({lc_expr, Location, Expr}) ->
#{type => lc_expr,
attrs => #{location => Location},
content => [to_map(Expr)]};

%% Operation

Expand Down
46 changes: 43 additions & 3 deletions src/elvis_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

-export([
src/2,

%% Files
find_files/1,
find_files/2,
is_erlang_file/1,
filter_files/1,

%% Rules
check_lines/3,
check_lines_with_context/4,
indentation/3,
check_nodes/3,

%% General
erlang_halt/1,
to_str/1,
is_erlang_file/1,
filter_files/1
to_str/1
]).

-export_type([file/0]).
Expand Down Expand Up @@ -57,6 +65,13 @@ check_lines(Src, Fun, Args) ->
Lines = binary:split(Src, <<"\n">>, [global]),
check_lines(Lines, Fun, Args, [], 1).

-spec check_lines_with_context(binary(), fun(), [term()], {integer(), integer()}) ->
[elvis_result:item()].
check_lines_with_context(Src, Fun, Args, Ctx) ->
Lines = binary:split(Src, <<"\n">>, [global]),
LinesContext = context(Lines, Ctx),
check_lines(LinesContext, Fun, Args, [], 1).

%% @private
check_lines([], _Fun, _Args, Results, _Num) ->
lists:reverse(Results);
Expand All @@ -68,6 +83,18 @@ check_lines([Line | Lines], Fun, Args, Results, Num) ->
check_lines(Lines, Fun, Args, Results, Num + 1)
end.

%% @private
context(List, CtxCount) ->
context(List, [], CtxCount, []).

context([], _Past, _CtxCount, Results) ->
lists:reverse(Results);
context([Current | Future], Past, CtxCount = {PrevCount, NextCount}, Results) ->
Prev = lists:sublist(Past, PrevCount),
Next = lists:sublist(Future, NextCount),
Item = {Current, lists:reverse(Prev), Next},
context(Future, [Current | Past], CtxCount, [Item | Results]).

%% @doc Takes a binary that holds source code and applies
%% Fun to each line. Fun takes 3 arguments (the line
%% as a binary, the line number and the supplied Args) and
Expand Down Expand Up @@ -114,3 +141,16 @@ is_erlang_file(Path) ->
filter_files(Files) ->
[File || File = #{path := Path} <- Files,
is_erlang_file(Path)].

%% @doc Takes a line, a character and a count, returning the indentation level
%% invalid if the number of character is not a multiple of count.
-spec indentation(binary() | string(), char(), integer()) ->
invalid | integer().
indentation(Line, Char, Count) ->
LineStr = to_str(Line),
Regex = "^" ++ [Char] ++ "*",
{match, [{0, Len} | _]} = re:run(LineStr, Regex),
case Len rem Count of
0 -> Len div Count;
_ -> invalid
end.
32 changes: 31 additions & 1 deletion test/examples/fail_nesting_level.erl
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ exceed_with_receive() ->
3 -> 3
end.

exceed_with_receive_after() ->
dont_exceed_with_receive_after() ->
case 1 of
1 -> ok;
2 -> receive
Expand All @@ -140,3 +140,33 @@ exceed_with_receive_after() ->
end;
3 -> 3
end.

dont_exceed_with_list_compr() ->
case 1 of
1 -> ok;
2 -> receive
1 -> ok;
2 -> ok;
3 -> ok
after
1000 ->
[X || X <- [1, 2, 3]]
end;
3 -> 3
end.

exceed_with_list_compr() ->
case 1 of
1 -> ok;
2 -> receive
1 -> ok;
2 -> ok;
3 -> [case X of
1 -> ok;
_ -> not_ok
end
|| X <- [1, 2, 3]];
4 -> ok
end;
3 -> 3
end.
3 changes: 2 additions & 1 deletion test/rules_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,5 @@ verify_nesting_level(_Config) ->
#{line_num := 28},
#{line_num := 43},
#{line_num := 76},
#{line_num := 118}] = elvis_style:nesting_level(ElvisConfig, File, [3]).
#{line_num := 118},
#{line_num := 164}] = elvis_style:nesting_level(ElvisConfig, File, [3]).

0 comments on commit 806b463

Please sign in to comment.