Skip to content

Commit 4883448

Browse files
author
José Valim
committed
Allow any function identifier as a variable, closes #1649
1 parent f02f90f commit 4883448

File tree

5 files changed

+38
-33
lines changed

5 files changed

+38
-33
lines changed

lib/elixir/src/elixir_parser.yrl

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ Nonterminals
1919
kw_eol kw_expr kw_comma kw
2020
call_args_no_parens_kw_expr call_args_no_parens_kw_comma call_args_no_parens_kw
2121
dot_op dot_alias dot_identifier dot_op_identifier dot_do_identifier
22-
dot_paren_identifier dot_punctuated_identifier dot_bracket_identifier
22+
dot_paren_identifier dot_bracket_identifier
2323
var list bracket_access bit_string tuple
2424
do_block fn_eol do_eol end_eol block_eol block_item block_list
2525
.
2626

2727
Terminals
28-
identifier kw_identifier punctuated_identifier
29-
bracket_identifier paren_identifier do_identifier block_identifier
28+
identifier kw_identifier bracket_identifier
29+
paren_identifier do_identifier block_identifier
3030
fn 'end' aliases
3131
number signed_number atom bin_string list_string sigil
3232
dot_call_op op_identifier
@@ -96,7 +96,6 @@ matched_expr -> at_op_eol no_parens_expr : build_unary_op('$1', '$2').
9696
matched_expr -> bracket_at_expr : '$1'.
9797
matched_expr -> identifier_expr : '$1'.
9898

99-
no_parens_expr -> dot_punctuated_identifier call_args_no_parens_many_strict : build_identifier('$1', '$2').
10099
no_parens_expr -> dot_op_identifier call_args_no_parens_many_strict : build_identifier('$1', '$2').
101100
no_parens_expr -> dot_identifier call_args_no_parens_many_strict : build_identifier('$1', '$2').
102101

@@ -110,7 +109,6 @@ unmatched_expr -> block_expr : '$1'.
110109
block_expr -> parens_call call_args_parens do_block : build_identifier('$1', '$2' ++ '$3').
111110
block_expr -> parens_call call_args_parens call_args_parens do_block : build_nested_parens('$1', '$2', '$3' ++ '$4').
112111
block_expr -> dot_do_identifier do_block : build_identifier('$1', '$2').
113-
block_expr -> dot_punctuated_identifier call_args_no_parens_all do_block : build_identifier('$1', '$2' ++ '$3').
114112
block_expr -> dot_identifier call_args_no_parens_all do_block : build_identifier('$1', '$2' ++ '$3').
115113

116114
op_expr -> match_op_eol expr : { '$1', '$2' }.
@@ -167,10 +165,8 @@ matched_op_expr -> type_op_eol matched_expr : { '$1', '$2' }.
167165
matched_op_expr -> comp_op_eol matched_expr : { '$1', '$2' }.
168166
matched_op_expr -> arrow_op_eol matched_expr : { '$1', '$2' }.
169167

170-
identifier_expr -> dot_punctuated_identifier call_args_no_parens_one : build_identifier('$1', '$2').
171168
identifier_expr -> dot_op_identifier call_args_no_parens_one : build_identifier('$1', '$2').
172169
identifier_expr -> dot_identifier call_args_no_parens_one : build_identifier('$1', '$2').
173-
identifier_expr -> dot_punctuated_identifier : build_identifier('$1', []).
174170
identifier_expr -> dot_do_identifier : build_identifier('$1', nil).
175171
identifier_expr -> var : build_identifier('$1', nil).
176172
identifier_expr -> max_expr : '$1'.
@@ -365,9 +361,6 @@ dot_bracket_identifier -> matched_expr dot_op bracket_identifier : build_dot('$2
365361
dot_paren_identifier -> paren_identifier : '$1'.
366362
dot_paren_identifier -> matched_expr dot_op paren_identifier : build_dot('$2', '$1', '$3').
367363

368-
dot_punctuated_identifier -> punctuated_identifier : '$1'.
369-
dot_punctuated_identifier -> matched_expr dot_op punctuated_identifier : build_dot('$2', '$1', '$3').
370-
371364
parens_call -> dot_paren_identifier : '$1'.
372365
parens_call -> matched_expr dot_call_op : { '.', [{line,?line('$2')}], ['$1'] }. % Fun/local calls
373366

@@ -546,8 +539,8 @@ build_identifier({ _, Line, Identifier }, Args) ->
546539
{ Identifier, [{line,Line}], Args }.
547540

548541
extract_identifier({ Kind, _, Identifier }) when
549-
Kind == identifier; Kind == punctuated_identifier; Kind == bracket_identifier;
550-
Kind == paren_identifier; Kind == do_identifier; Kind == op_identifier ->
542+
Kind == identifier; Kind == bracket_identifier; Kind == paren_identifier;
543+
Kind == do_identifier; Kind == op_identifier ->
551544
Identifier;
552545

553546
extract_identifier(Other) -> Other.

lib/elixir/src/elixir_tokenizer.erl

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ tokenize([Space, Sign, NotMarker|T], Line, Scope, [{ Identifier, _, _ } = H|Toke
507507
?is_horizontal_space(Space),
508508
not(?is_space(NotMarker)),
509509
NotMarker /= $(, NotMarker /= $+, NotMarker /= $-, NotMarker /= $>,
510-
Identifier == identifier orelse Identifier == punctuated_identifier ->
510+
Identifier == identifier ->
511511
Rest = [NotMarker|T],
512512
tokenize(Rest, Line, Scope, [{ dual_op, Line, list_to_atom([Sign]) }, setelement(1, H, op_identifier)|Tokens]);
513513

@@ -787,21 +787,17 @@ tokenize_identifier(Rest, Acc) ->
787787
tokenize_any_identifier(String, Line, Scope, Tokens) ->
788788
{ Rest, Identifier } = tokenize_identifier(String, []),
789789

790-
case Rest of
791-
[H|T] when H == $?; H == $! ->
792-
case unsafe_to_atom(Identifier ++ [H], Line, Scope) of
793-
{ error, _ } = Error ->
794-
Error;
795-
Atom ->
796-
tokenize_kw_or_other(T, punctuated_identifier, Line, Atom, Tokens)
797-
end;
798-
_ ->
799-
case unsafe_to_atom(Identifier, Line, Scope) of
800-
{ error, _ } = Error ->
801-
Error;
802-
Atom ->
803-
tokenize_kw_or_other(Rest, identifier, Line, Atom, Tokens)
804-
end
790+
{ AllIdentifier, AllRest } =
791+
case Rest of
792+
[H|T] when H == $?; H == $! -> { Identifier ++ [H], T };
793+
_ -> { Identifier, Rest }
794+
end,
795+
796+
case unsafe_to_atom(AllIdentifier, Line, Scope) of
797+
{ error, _ } = Error ->
798+
Error;
799+
Atom ->
800+
tokenize_kw_or_other(AllRest, identifier, Line, Atom, Tokens)
805801
end.
806802

807803
tokenize_kw_or_other([$:,H|T], _Kind, Line, Atom, _Tokens) when ?is_space(H) ->
@@ -905,8 +901,7 @@ terminator('<<') -> '>>'.
905901
check_keyword(_Line, _Atom, [{ '.', _ }|_]) ->
906902
nomatch;
907903

908-
check_keyword(Line, do, [{ Identifier, Line, Atom }|T]) when
909-
Identifier == identifier; Identifier == punctuated_identifier ->
904+
check_keyword(Line, do, [{ Identifier, Line, Atom }|T]) when Identifier == identifier ->
910905
{ ok, [{ do, Line }, { do_identifier, Line, Atom }|T] };
911906

912907
check_keyword(Line, do, Tokens) ->

lib/elixir/test/elixir/kernel/fn_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ defmodule Kernel.FnTest do
2525
assert (&atl(&1)).(:a) == 'a'
2626
end
2727

28+
test "capture local with question mark" do
29+
assert (&is_a?/2).(:atom, :a)
30+
assert (&(is_a?/2)).(:atom, :a)
31+
assert (&is_a?(&1, &2)).(:atom, :a)
32+
end
33+
2834
test "capture imported" do
2935
assert (&atom_to_list/1).(:a) == 'a'
3036
assert (&(atom_to_list/1)).(:a) == 'a'
@@ -114,6 +120,9 @@ defmodule Kernel.FnTest do
114120
"&foo()"
115121
end
116122

123+
defp is_a?(:atom, atom) when is_atom(atom), do: true
124+
defp is_a?(_, _), do: false
125+
117126
defp atl(arg) do
118127
:erlang.atom_to_list arg
119128
end

lib/elixir/test/elixir/kernel_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ Code.require_file "test_helper.exs", __DIR__
33
defmodule KernelTest do
44
use ExUnit.Case, async: true
55

6+
test :vars do
7+
foo? = true
8+
assert foo?
9+
10+
bar! = false
11+
refute bar!
12+
end
13+
614
test :match do
715
assert ("abcd" =~ %r/c(d)/) == true
816
assert ("abcd" =~ %r/e/) == false

lib/elixir/test/erlang/tokenizer_test.erl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ comments_test() ->
7474

7575
identifier_test() ->
7676
[{identifier,1,abc}] = tokenize("abc "),
77-
[{punctuated_identifier,1,'abc?'}] = tokenize("abc?"),
78-
[{punctuated_identifier,1,'abc!'}] = tokenize("abc!"),
79-
[{punctuated_identifier,1,'a0c!'}] = tokenize("a0c!"),
77+
[{identifier,1,'abc?'}] = tokenize("abc?"),
78+
[{identifier,1,'abc!'}] = tokenize("abc!"),
79+
[{identifier,1,'a0c!'}] = tokenize("a0c!"),
8080
[{paren_identifier,1,'a0c'},{'(',1},{')',1}] = tokenize("a0c()"),
8181
[{paren_identifier,1,'a0c!'},{'(',1},{')',1}] = tokenize("a0c!()").
8282

0 commit comments

Comments
 (0)