Skip to content

Commit 0d4655d

Browse files
author
José Valim
committed
Generalize unary operators followed by int have higher precedence
1 parent e42e3e5 commit 0d4655d

File tree

3 files changed

+20
-21
lines changed

3 files changed

+20
-21
lines changed

lib/elixir/src/elixir_parser.yrl

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Terminals
3131
dot_call_op op_identifier
3232
comp_op at_op unary_op and_op or_op arrow_op match_op in_op in_match_op
3333
dual_op add_op mult_op exp_op two_op pipe_op stab_op when_op
34-
'true' 'false' 'nil' 'do' eol ',' '.' '&'
34+
'true' 'false' 'nil' 'do' eol ',' '.'
3535
'(' ')' '[' ']' '{' '}' '<<' '>>'
3636
.
3737

@@ -105,6 +105,7 @@ expr -> unmatched_expr : '$1'.
105105
%% segments and act accordingly.
106106
matched_expr -> matched_expr matched_op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
107107
matched_expr -> matched_expr no_parens_op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
108+
matched_expr -> unary_op_eol number : build_unary_op('$1', ?exprs('$2')).
108109
matched_expr -> unary_op_eol matched_expr : build_unary_op('$1', '$2').
109110
matched_expr -> unary_op_eol no_parens_expr : build_unary_op('$1', '$2').
110111
matched_expr -> at_op_eol matched_expr : build_unary_op('$1', '$2').
@@ -210,7 +211,6 @@ base_expr -> list_string : build_list_string('$1').
210211
base_expr -> atom_string : build_atom_string('$1').
211212
base_expr -> bit_string : '$1'.
212213
base_expr -> sigil : build_sigil('$1').
213-
base_expr -> '&' number : { '&', meta('$1'), [?exprs('$2')] }.
214214

215215
%% Blocks
216216

@@ -244,7 +244,7 @@ stab_expr -> call_args_no_parens_all stab_op_eol stab_maybe_expr :
244244
stab_expr -> stab_parens_many stab_op_eol stab_maybe_expr :
245245
build_op('$2', unwrap_splice('$1'), '$3').
246246
stab_expr -> stab_parens_many when_op expr stab_op_eol stab_maybe_expr :
247-
build_op('$4', [{ 'when', meta('$2'), unwrap_splice('$1') ++ ['$3'] }], '$5').
247+
build_op('$4', [{ 'when', meta('$2'), unwrap_splice('$1') ++ ['$3'] }], '$5').
248248

249249
stab_maybe_expr -> 'expr' : '$1'.
250250
stab_maybe_expr -> '$empty' : nil.
@@ -459,9 +459,7 @@ Erlang code.
459459
-define(line(Node), element(2, Node)).
460460
-define(exprs(Node), element(3, Node)).
461461
-define(lexical(Kind), Kind == import; Kind == alias; Kind == '__aliases__').
462-
463462
-define(rearrange_uop(Op), Op == 'not' orelse Op == '!').
464-
-define(rearrange_bop(Op), Op == 'in' orelse Op == 'inlist' orelse Op == 'inbits').
465463

466464
%% The following directive is needed for (significantly) faster
467465
%% compilation of the generated .erl file by the HiPE compiler
@@ -479,8 +477,8 @@ build_op({ _Kind, Line, '/' }, { '&', _, [{ Kind, _, Atom } = Left] }, Right) wh
479477
build_op({ _Kind, Line, '/' }, { '&', _, [{ { '.', _, [_, _] }, _, [] } = Left] }, Right) when is_number(Right) ->
480478
{ '&', meta(Line), [{ '/', meta(Line), [Left, Right] }] };
481479

482-
build_op({ _Kind, Line, BOp }, { UOp, _, [Left] }, Right) when ?rearrange_bop(BOp), ?rearrange_uop(UOp) ->
483-
{ UOp, meta(Line), [{ BOp, meta(Line), [Left, Right] }] };
480+
build_op({ _Kind, Line, 'in' }, { UOp, _, [Left] }, Right) when ?rearrange_uop(UOp) ->
481+
{ UOp, meta(Line), [{ 'in', meta(Line), [Left, Right] }] };
484482

485483
build_op({ _Kind, Line, Op }, Left, Right) ->
486484
{ Op, meta(Line), [Left, Right] }.
@@ -513,11 +511,17 @@ build_dot_alias(Dot, Other, { 'aliases', _, Right }) ->
513511
build_dot(Dot, Left, Right) ->
514512
{ '.', meta(Dot), [Left, extract_identifier(Right)] }.
515513

514+
extract_identifier({ Kind, _, Identifier }) when
515+
Kind == identifier; Kind == bracket_identifier; Kind == paren_identifier;
516+
Kind == do_identifier; Kind == op_identifier ->
517+
Identifier.
518+
516519
%% Identifiers
517520

518521
build_nested_parens(Dot, Args1, Args2) ->
519522
Identifier = build_identifier(Dot, Args1),
520-
{ Identifier, ?line(Identifier), Args2 }.
523+
Meta = element(2, Identifier),
524+
{ Identifier, Meta, Args2 }.
521525

522526
build_identifier({ '.', Meta, _ } = Dot, Args) ->
523527
FArgs = case Args of
@@ -538,13 +542,6 @@ build_identifier({ _, Line, Identifier }, Args) when ?lexical(Identifier) ->
538542
build_identifier({ _, Line, Identifier }, Args) ->
539543
{ Identifier, meta(Line), Args }.
540544

541-
extract_identifier({ Kind, _, Identifier }) when
542-
Kind == identifier; Kind == bracket_identifier; Kind == paren_identifier;
543-
Kind == do_identifier; Kind == op_identifier ->
544-
Identifier;
545-
546-
extract_identifier(Other) -> Other.
547-
548545
%% Fn
549546

550547
build_fn(Op, Stab) ->

lib/elixir/src/elixir_tokenizer.erl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,10 +354,6 @@ tokenize([T1,T2|Rest], Line, Scope, Tokens) when ?stab_op(T1, T2) ->
354354

355355
% ## Single Token Operators
356356

357-
%% Handle &1 and friends with special precedence.
358-
tokenize([$&,D|Rest], Line, Scope, Tokens) when ?is_digit(D) ->
359-
tokenize([D|Rest], Line, Scope, [{ '&', Line }|Tokens]);
360-
361357
tokenize([T|Rest], Line, Scope, Tokens) when ?at_op(T) ->
362358
handle_unary_op(Rest, Line, at_op, list_to_atom([T]), Scope, Tokens);
363359

lib/elixir/test/elixir/kernel/quote_test.exs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ defmodule Kernel.QuoteTest do
151151
test :with_dynamic_opts do
152152
assert quote(dynamic_opts, do: bar(1, 2, 3)) == { :bar, [line: 3], [1, 2, 3] }
153153
end
154+
155+
test :unary_with_integer_precedence do
156+
assert quote(do: +1.foo) == quote(do: (+1).foo)
157+
assert quote(do: @1.foo) == quote(do: (@1).foo)
158+
assert quote(do: &1.foo) == quote(do: (&1).foo)
159+
end
154160
end
155161

156162
## DO NOT MOVE THIS LINE
@@ -180,7 +186,7 @@ defmodule Kernel.QuoteTest.ErrorsTest do
180186

181187
mod = Kernel.QuoteTest.ErrorsTest
182188
file = __ENV__.file |> Path.relative_to_cwd |> String.to_char_list!
183-
assert [{ ^mod, :add, 2, [file: ^file, line: 160] }|_] = System.stacktrace
189+
assert [{ ^mod, :add, 2, [file: ^file, line: 166] }|_] = System.stacktrace
184190
end
185191

186192
test :outside_function_error do
@@ -190,7 +196,7 @@ defmodule Kernel.QuoteTest.ErrorsTest do
190196

191197
mod = Kernel.QuoteTest.ErrorsTest
192198
file = __ENV__.file |> Path.relative_to_cwd |> String.to_char_list!
193-
assert [{ ^mod, _, _, [file: ^file, line: 188] }|_] = System.stacktrace
199+
assert [{ ^mod, _, _, [file: ^file, line: 194] }|_] = System.stacktrace
194200
end
195201
end
196202

0 commit comments

Comments
 (0)