Skip to content

Commit 6655d40

Browse files
committed
Streamline and document the parser
1 parent d68c8d6 commit 6655d40

File tree

4 files changed

+38
-29
lines changed

4 files changed

+38
-29
lines changed

lib/elixir/lib/code/formatter.ex

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ defmodule Code.Formatter do
634634

635635
defp maybe_binary_op_to_algebra(fun, meta, args, context, state) do
636636
with [left, right] <- args,
637-
{_, _} <- Code.Identifier.binary_op(fun) do
637+
{_, _} <- augmented_binary_op(fun) do
638638
binary_op_to_algebra(fun, Atom.to_string(fun), meta, left, right, context, state)
639639
else
640640
_ -> :error
@@ -661,7 +661,7 @@ defmodule Code.Formatter do
661661

662662
defp binary_op_to_algebra(op, op_string, meta, left_arg, right_arg, context, state, _nesting)
663663
when op in @right_new_line_before_binary_operators do
664-
op_info = Code.Identifier.binary_op(op)
664+
op_info = augmented_binary_op(op)
665665
op_string = op_string <> " "
666666
left_context = left_op_context(context)
667667
right_context = right_op_context(context)
@@ -698,7 +698,7 @@ defmodule Code.Formatter do
698698

699699
defp binary_op_to_algebra(op, _, meta, left_arg, right_arg, context, state, _nesting)
700700
when op in @pipeline_operators do
701-
op_info = Code.Identifier.binary_op(op)
701+
op_info = augmented_binary_op(op)
702702
left_context = left_op_context(context)
703703
right_context = right_op_context(context)
704704
max_line = line(meta)
@@ -712,7 +712,7 @@ defmodule Code.Formatter do
712712
{{doc, @empty, 1}, state}
713713

714714
{{op, context}, arg}, _args, state ->
715-
op_info = Code.Identifier.binary_op(op)
715+
op_info = augmented_binary_op(op)
716716
op_string = Atom.to_string(op) <> " "
717717
{doc, state} = binary_operand_to_algebra(arg, context, state, op, op_info, :right, 0)
718718
{{concat(op_string, doc), @empty, 1}, state}
@@ -722,7 +722,7 @@ defmodule Code.Formatter do
722722
end
723723

724724
defp binary_op_to_algebra(op, op_string, meta, left_arg, right_arg, context, state, nesting) do
725-
op_info = Code.Identifier.binary_op(op)
725+
op_info = augmented_binary_op(op)
726726
left_context = left_op_context(context)
727727
right_context = right_op_context(context)
728728

@@ -781,7 +781,7 @@ defmodule Code.Formatter do
781781
{parent_assoc, parent_prec} = parent_info
782782

783783
with {op, meta, [left, right]} <- operand,
784-
op_info = Code.Identifier.binary_op(op),
784+
op_info = augmented_binary_op(op),
785785
{_assoc, prec} <- op_info do
786786
op_string = Atom.to_string(op)
787787

@@ -2192,10 +2192,15 @@ defmodule Code.Formatter do
21922192
unary_operator?(quoted) or binary_operator?(quoted)
21932193
end
21942194

2195+
# We convert ..// into two operators for simplicity,
2196+
# so we need to augment the binary table.
2197+
defp augmented_binary_op(:"//"), do: {:right, 190}
2198+
defp augmented_binary_op(op), do: Code.Identifier.binary_op(op)
2199+
21952200
defp binary_operator?(quoted) do
21962201
case quoted do
21972202
{op, _, [_, _, _]} when op in @multi_binary_operators -> true
2198-
{op, _, [_, _]} when is_atom(op) -> Code.Identifier.binary_op(op) != :error
2203+
{op, _, [_, _]} when is_atom(op) -> augmented_binary_op(op) != :error
21992204
_ -> false
22002205
end
22012206
end

lib/elixir/lib/code/identifier.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ defmodule Code.Identifier do
4444
op in [:|>, :<<<, :>>>, :<~, :~>, :<<~, :~>>, :<~>, :"<|>"] -> {:left, 160}
4545
op in [:in] -> {:left, 170}
4646
op in [:"^^^"] -> {:left, 180}
47-
op in [:"//"] -> {:right, 190}
4847
op in [:++, :--, :.., :<>, :+++, :---] -> {:right, 200}
4948
op in [:+, :-] -> {:left, 210}
5049
op in [:*, :/] -> {:left, 220}

lib/elixir/src/elixir_parser.yrl

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,11 @@ expr -> unmatched_expr : '$1'.
143143
%% if calls without parentheses are do blocks in particular
144144
%% segments and act accordingly.
145145
matched_expr -> matched_expr matched_op_expr : build_op('$1', '$2').
146-
matched_expr -> no_parens_one_expr : '$1'.
147146
matched_expr -> unary_op_eol matched_expr : build_unary_op('$1', '$2').
148147
matched_expr -> at_op_eol matched_expr : build_unary_op('$1', '$2').
149148
matched_expr -> capture_op_eol matched_expr : build_unary_op('$1', '$2').
150149
matched_expr -> ellipsis_op matched_expr : build_unary_op('$1', '$2').
150+
matched_expr -> no_parens_one_expr : '$1'.
151151
matched_expr -> sub_matched_expr : '$1'.
152152

153153
unmatched_expr -> matched_expr unmatched_op_expr : build_op('$1', '$2').
@@ -192,6 +192,10 @@ matched_op_expr -> pipe_op_eol matched_expr : {'$1', '$2'}.
192192
matched_op_expr -> comp_op_eol matched_expr : {'$1', '$2'}.
193193
matched_op_expr -> rel_op_eol matched_expr : {'$1', '$2'}.
194194
matched_op_expr -> arrow_op_eol matched_expr : {'$1', '$2'}.
195+
196+
%% We warn exclusively for |> and friends because they are used
197+
%% in other languages with lower precedence than function application,
198+
%% which can be the source of confusion.
195199
matched_op_expr -> arrow_op_eol no_parens_one_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.
196200

197201
unmatched_op_expr -> match_op_eol unmatched_expr : {'$1', '$2'}.
@@ -230,9 +234,7 @@ no_parens_op_expr -> when_op_eol no_parens_expr : {'$1', '$2'}.
230234
no_parens_op_expr -> pipe_op_eol no_parens_expr : {'$1', '$2'}.
231235
no_parens_op_expr -> comp_op_eol no_parens_expr : {'$1', '$2'}.
232236
no_parens_op_expr -> rel_op_eol no_parens_expr : {'$1', '$2'}.
233-
no_parens_op_expr -> arrow_op_eol no_parens_expr : {'$1', '$2'}.
234-
no_parens_op_expr -> arrow_op_eol no_parens_one_ambig_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.
235-
no_parens_op_expr -> arrow_op_eol no_parens_many_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.
237+
no_parens_op_expr -> arrow_op_eol no_parens_expr : warn_pipe('$1', '$2'), {'$1', '$2'}.
236238

237239
%% Allow when (and only when) with keywords
238240
no_parens_op_expr -> when_op_eol call_args_no_parens_kw : {'$1', '$2'}.
@@ -245,8 +247,8 @@ no_parens_many_expr -> dot_identifier call_args_no_parens_many_strict : build_no
245247

246248
no_parens_one_expr -> dot_op_identifier call_args_no_parens_one : build_no_parens('$1', '$2').
247249
no_parens_one_expr -> dot_identifier call_args_no_parens_one : build_no_parens('$1', '$2').
248-
no_parens_zero_expr -> dot_do_identifier : build_no_parens('$1', nil).
249-
no_parens_zero_expr -> dot_identifier : build_no_parens('$1', nil).
250+
no_parens_zero_expr -> dot_do_identifier : build_identifier('$1').
251+
no_parens_zero_expr -> dot_identifier : build_identifier('$1').
250252

251253
sub_matched_expr -> no_parens_zero_expr : '$1'.
252254
sub_matched_expr -> range_op : build_nullary_op('$1').
@@ -299,11 +301,11 @@ bracket_arg -> open_bracket container_expr close_bracket : build_access_arg('$1'
299301
bracket_arg -> open_bracket container_expr ',' close_bracket : build_access_arg('$1', '$2', '$4').
300302
bracket_arg -> open_bracket container_expr ',' container_args close_bracket : error_too_many_access_syntax('$3').
301303

302-
bracket_expr -> dot_bracket_identifier bracket_arg : build_access(build_no_parens('$1', nil), meta_with_from_brackets('$2')).
304+
bracket_expr -> dot_bracket_identifier bracket_arg : build_access(build_identifier('$1'), meta_with_from_brackets('$2')).
303305
bracket_expr -> access_expr bracket_arg : build_access('$1', meta_with_from_brackets('$2')).
304306

305307
bracket_at_expr -> at_op_eol dot_bracket_identifier bracket_arg :
306-
build_access(build_unary_op('$1', build_no_parens('$2', nil)), meta_with_from_brackets('$3')).
308+
build_access(build_unary_op('$1', build_identifier('$2')), meta_with_from_brackets('$3')).
307309
bracket_at_expr -> at_op_eol access_expr bracket_arg :
308310
build_access(build_unary_op('$1', '$2'), meta_with_from_brackets('$3')).
309311

@@ -897,32 +899,35 @@ build_nested_parens(Dot, Args1, {Args2Meta, Args2}, {BlockMeta, Block}) ->
897899
{Identifier, Meta, append_non_empty(Args2, Block)}.
898900

899901
build_parens(Expr, {ArgsMeta, Args}, {BlockMeta, Block}) ->
900-
{BuiltExpr, BuiltMeta, BuiltArgs} = build_identifier(Expr, append_non_empty(Args, Block)),
902+
{BuiltExpr, BuiltMeta, BuiltArgs} = build_call(Expr, append_non_empty(Args, Block)),
901903
{BuiltExpr, BlockMeta ++ ArgsMeta ++ BuiltMeta, BuiltArgs}.
902904

903905
build_no_parens_do_block(Expr, Args, {BlockMeta, Block}) ->
904-
{BuiltExpr, BuiltMeta, BuiltArgs} = build_no_parens(Expr, Args ++ Block),
906+
{BuiltExpr, BuiltMeta, BuiltArgs} = build_call(Expr, Args ++ Block),
905907
{BuiltExpr, BlockMeta ++ BuiltMeta, BuiltArgs}.
906908

907909
build_no_parens(Expr, Args) ->
908-
build_identifier(Expr, Args).
910+
build_call(Expr, Args).
909911

910-
build_identifier({'.', Meta, IdentifierLocation, DotArgs}, nil) ->
912+
build_identifier({'.', Meta, IdentifierLocation, DotArgs}) ->
911913
{{'.', Meta, DotArgs}, [{no_parens, true} | IdentifierLocation], []};
912914

913-
build_identifier({'.', Meta, IdentifierLocation, DotArgs}, Args) ->
914-
{{'.', Meta, DotArgs}, IdentifierLocation, Args};
915-
916-
build_identifier({'.', Meta, _} = Dot, nil) ->
915+
build_identifier({'.', Meta, _} = Dot) ->
917916
{Dot, [{no_parens, true} | Meta], []};
918917

919-
build_identifier({'.', Meta, _} = Dot, Args) ->
918+
build_identifier({_, Location, Identifier}) ->
919+
{Identifier, meta_from_location(Location), nil}.
920+
921+
build_call({'.', Meta, IdentifierLocation, DotArgs}, Args) ->
922+
{{'.', Meta, DotArgs}, IdentifierLocation, Args};
923+
924+
build_call({'.', Meta, _} = Dot, Args) ->
920925
{Dot, Meta, Args};
921926

922-
build_identifier({op_identifier, Location, Identifier}, [Arg]) ->
927+
build_call({op_identifier, Location, Identifier}, [Arg]) ->
923928
{Identifier, [{ambiguous_op, nil} | meta_from_location(Location)], [Arg]};
924929

925-
build_identifier({_, Location, Identifier}, Args) ->
930+
build_call({_, Location, Identifier}, Args) ->
926931
{Identifier, meta_from_location(Location), Args}.
927932

928933
%% Fn

lib/elixir/src/elixir_tokenizer.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -872,14 +872,14 @@ handle_op(Rest, Line, Column, Kind, Length, Op, Scope, Tokens) ->
872872
% ## Three Token Operators
873873
handle_dot([$., T1, T2, T3 | Rest], Line, Column, DotInfo, Scope, Tokens) when
874874
?unary_op3(T1, T2, T3); ?comp_op3(T1, T2, T3); ?and_op3(T1, T2, T3); ?or_op3(T1, T2, T3);
875-
?arrow_op3(T1, T2, T3); ?xor_op3(T1, T2, T3); ?concat_op3(T1, T2, T3); ?ellipsis_op3(T1, T2, T3) ->
875+
?arrow_op3(T1, T2, T3); ?xor_op3(T1, T2, T3); ?concat_op3(T1, T2, T3) ->
876876
handle_call_identifier(Rest, Line, Column, DotInfo, 3, [T1, T2, T3], Scope, Tokens);
877877

878878
% ## Two Token Operators
879879
handle_dot([$., T1, T2 | Rest], Line, Column, DotInfo, Scope, Tokens) when
880880
?comp_op2(T1, T2); ?rel_op2(T1, T2); ?and_op(T1, T2); ?or_op(T1, T2);
881881
?arrow_op(T1, T2); ?in_match_op(T1, T2); ?concat_op(T1, T2); ?power_op(T1, T2);
882-
?type_op(T1, T2); ?range_op(T1, T2) ->
882+
?type_op(T1, T2) ->
883883
handle_call_identifier(Rest, Line, Column, DotInfo, 2, [T1, T2], Scope, Tokens);
884884

885885
% ## Single Token Operators

0 commit comments

Comments
 (0)