Skip to content

Commit bd7d428

Browse files
Add metadata about single-expression block closing/opening (#13940)
1 parent 322159c commit bd7d428

File tree

2 files changed

+75
-11
lines changed

2 files changed

+75
-11
lines changed

lib/elixir/src/elixir_parser.yrl

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -672,15 +672,15 @@ meta_from_location({Line, Column, _}) ->
672672
do_end_meta(Do, End) ->
673673
case ?token_metadata() of
674674
true ->
675-
[{do, meta_from_location(?location(Do))}, {'end', meta_from_location(?location(End))}];
675+
[{do, meta_from_token(Do)}, {'end', meta_from_token(End)}];
676676
false ->
677677
[]
678678
end.
679679

680680
meta_from_token_with_closing(Begin, End) ->
681681
case ?token_metadata() of
682682
true ->
683-
[{closing, meta_from_location(?location(End))} | meta_from_token(Begin)];
683+
[{closing, meta_from_token(End)} | meta_from_token(Begin)];
684684
false ->
685685
meta_from_token(Begin)
686686
end.
@@ -778,21 +778,42 @@ build_map_update(Left, {Pipe, Struct, Map}, Right, Extra) ->
778778

779779
%% Blocks
780780

781-
build_block(Exprs) -> build_block(Exprs, []).
781+
build_block(Exprs) -> build_block(Exprs, none).
782782

783-
build_block([{unquote_splicing, _, [_]}]=Exprs, Meta) ->
784-
{'__block__', Meta, Exprs};
785-
build_block([Expr], _Meta) ->
783+
build_block([{unquote_splicing, _, [_]}]=Exprs, BeforeAfter) ->
784+
{'__block__', block_meta(BeforeAfter), Exprs};
785+
build_block([{Op, ExprMeta, Args}], {Before, After}) ->
786+
ExprMetaWithExtra =
787+
case ?token_metadata() of
788+
true ->
789+
ParensEntry = meta_from_token(Before) ++ [{closing, meta_from_token(After)}],
790+
case ExprMeta of
791+
% If there are multiple parens, those will result in subsequent
792+
% build_block/2 calls, so we can assume parens entry is first
793+
[{parens, Parens} | Meta] ->
794+
[{parens, [ParensEntry | Parens]} | Meta];
795+
796+
Meta ->
797+
[{parens, [ParensEntry]} | Meta]
798+
end;
799+
false ->
800+
ExprMeta
801+
end,
802+
{Op, ExprMetaWithExtra, Args};
803+
build_block([Expr], _BeforeAfter) ->
786804
Expr;
787-
build_block(Exprs, Meta) ->
788-
{'__block__', Meta, Exprs}.
805+
build_block(Exprs, BeforeAfter) ->
806+
{'__block__', block_meta(BeforeAfter), Exprs}.
807+
808+
block_meta(none) -> [];
809+
block_meta({Before, After}) -> meta_from_token_with_closing(Before, After).
789810

790811
%% Newlines
791812

792813
newlines_pair(Left, Right) ->
793814
case ?token_metadata() of
794815
true ->
795-
newlines(?location(Left), [{closing, meta_from_location(?location(Right))}]);
816+
newlines(?location(Left), [{closing, meta_from_token(Right)}]);
796817
false ->
797818
[]
798819
end.
@@ -1064,7 +1085,7 @@ build_paren_stab(_Before, [{Op, _, [_]}]=Exprs, _After) when ?rearrange_uop(Op)
10641085
{'__block__', [], Exprs};
10651086
build_paren_stab(Before, Stab, After) ->
10661087
case check_stab(Stab, none) of
1067-
block -> build_block(reverse(Stab), meta_from_token_with_closing(Before, After));
1088+
block -> build_block(reverse(Stab), {Before, After});
10681089
stab -> handle_literal(collect_stab(Stab, [], []), Before, newlines_pair(Before, After))
10691090
end.
10701091

lib/elixir/test/elixir/kernel/parser_test.exs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,39 @@ defmodule Kernel.ParserTest do
609609
[[do: {:__block__, [], []}]]}
610610
end
611611

612+
test "adds opening and closing information for single-expression block" do
613+
file = "1 + (2 + 3)"
614+
615+
assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==
616+
{:+, [line: 1, column: 3],
617+
[
618+
1,
619+
{:+,
620+
[
621+
parens: [[line: 1, column: 5, closing: [line: 1, column: 11]]],
622+
line: 1,
623+
column: 8
624+
], [2, 3]}
625+
]}
626+
627+
file = "1 + ((2 + 3))"
628+
629+
assert Code.string_to_quoted!(file, token_metadata: true, columns: true) ==
630+
{:+, [line: 1, column: 3],
631+
[
632+
1,
633+
{:+,
634+
[
635+
parens: [
636+
[line: 1, column: 5, closing: [line: 1, column: 13]],
637+
[line: 1, column: 6, closing: [line: 1, column: 12]]
638+
],
639+
line: 1,
640+
column: 9
641+
], [2, 3]}
642+
]}
643+
end
644+
612645
test "with :literal_encoder" do
613646
opts = [literal_encoder: &{:ok, {:__block__, &2, [&1]}}, token_metadata: true]
614647
string_to_quoted = &Code.string_to_quoted!(&1, opts)
@@ -646,10 +679,20 @@ defmodule Kernel.ParserTest do
646679
[
647680
{:->, [line: 1],
648681
[
649-
[{:__block__, [token: "1", line: 1], [1]}],
682+
[
683+
{:__block__,
684+
[
685+
parens: [[line: 1, closing: [line: 1]]],
686+
token: "1",
687+
line: 1
688+
], [1]}
689+
],
650690
{:__block__, [delimiter: "\"", line: 1], ["hello"]}
651691
]}
652692
]}
693+
694+
assert string_to_quoted.("(1)") ==
695+
{:__block__, [parens: [[line: 1, closing: [line: 1]]], token: "1", line: 1], [1]}
653696
end
654697

655698
test "adds identifier_location for qualified identifiers" do

0 commit comments

Comments
 (0)