@@ -328,12 +328,9 @@ defmodule Gradient.AstSpecifier do
328
328
def mapper ( { :call , anno , name , args } , tokens , opts ) do
329
329
# anno has correct line
330
330
{ :ok , _ , anno , opts , _ } = get_line ( anno , opts )
331
-
332
331
name = remote_mapper ( name )
333
332
334
- { opts , args } = call_with_pipe_op ( tokens , args , opts )
335
-
336
- { args , tokens } = context_mapper_fold ( args , tokens , opts )
333
+ { args , tokens } = call_args_mapper ( args , tokens , name , opts )
337
334
338
335
{ :call , anno , name , args }
339
336
|> pass_tokens ( tokens )
@@ -388,8 +385,7 @@ defmodule Gradient.AstSpecifier do
388
385
end
389
386
390
387
def mapper ( { type , anno , value } , tokens , opts )
391
- when type in [ :atom , :char , :float , :integer , :string , :bin ] do
392
- # TODO check what happened for :string
388
+ when type in @ lineless_forms do
393
389
{ :ok , line } = Keyword . fetch ( opts , :line )
394
390
anno = :erl_anno . set_line ( line , anno )
395
391
anno = :erl_anno . set_generated ( Keyword . get ( opts , :generated , false ) , anno )
@@ -594,6 +590,29 @@ defmodule Gradient.AstSpecifier do
594
590
end
595
591
end
596
592
593
+ @ doc """
594
+ Update location in call args with the support to the pipe operator.
595
+ """
596
+ @ spec call_args_mapper ( [ abstract_expr ( ) ] , tokens ( ) , abstract_expr ( ) , options ( ) ) ::
597
+ { options , [ abstract_expr ] }
598
+ def call_args_mapper ( args , tokens , name , opts ) do
599
+ # Check whether the call is after |> operator. If true, the parent location is set to 0
600
+ # and the first arg location is cleared (if this arg is a lineless form).
601
+ # NOTE If the call is to function from :erlang module then the first arg is swapped
602
+ # with the second one because in Erlang the data is mostly in the second place.
603
+ with true <- is_pipe_op? ( tokens , opts ) ,
604
+ swapped? <- is_call_to_erlang? ( name ) ,
605
+ [ fst_arg | tail_args ] <- maybe_swap_args ( swapped? , args ) ,
606
+ true <- is_lineless? ( fst_arg ) do
607
+ { arg , tokens } = mapper ( clear_location ( fst_arg ) , tokens , Keyword . put ( opts , :line , 0 ) )
608
+ { args , tokens } = context_mapper_fold ( tail_args , tokens , opts )
609
+ { maybe_swap_args ( swapped? , [ arg | args ] ) , tokens }
610
+ else
611
+ _ ->
612
+ context_mapper_fold ( args , tokens , opts )
613
+ end
614
+ end
615
+
597
616
# Private Helpers
598
617
599
618
@ spec match_token_to_form ( token ( ) , form ( ) ) :: boolean ( )
@@ -790,32 +809,22 @@ defmodule Gradient.AstSpecifier do
790
809
{ form , tokens }
791
810
end
792
811
793
- @ spec call_with_pipe_op ( tokens ( ) , [ abstract_expr ( ) ] , options ( ) ) :: { options , [ abstract_expr ] }
794
- def call_with_pipe_op ( tokens , args , opts ) do
795
- # Check whether the call is after |> operator. If true, the parent location is set to 0
796
- # and the first arg location is cleared (if this arg is a lineless form).
797
- # Clearing the location is required only for Elixir 1.13 or newer because from this version
798
- # the missing locations are specified, unfortunately sometimes not precise enough.
799
- { :ok , line } = Keyword . fetch ( opts , :line )
800
-
801
- case { List . first ( drop_tokens_to_line ( tokens , line ) ) , is_first_arg_lineless? ( args ) } do
802
- { { :arrow_op , _loc , :|> } , true } ->
803
- { Keyword . put ( opts , :line , 0 ) , clear_first_arg_location ( args ) }
804
-
805
- _ ->
806
- { opts , args }
812
+ defp is_pipe_op? ( tokens , opts ) do
813
+ case List . first ( drop_tokens_to_line ( tokens , Keyword . fetch! ( opts , :line ) ) ) do
814
+ { :arrow_op , _ , :|> } -> true
815
+ _ -> false
807
816
end
808
817
end
809
818
810
- def is_first_arg_lineless? ( [ form | _ ] ) , do: is_lineless_form? ( form )
811
- def is_first_arg_lineless? ( [ ] ) , do: false
819
+ defp maybe_swap_args ( true , [ fst , snd | t ] ) , do: [ snd , fst | t ]
820
+ defp maybe_swap_args ( _ , args ) , do: args
812
821
813
- def is_lineless_form? ( form ) do
814
- elem ( form , 0 ) in @ lineless_forms
815
- end
822
+ defp is_call_to_erlang? ( { :remote , _ , { :atom , _ , :erlang } , _ } ) , do: true
823
+ defp is_call_to_erlang? ( _ ) , do: false
816
824
817
- def clear_first_arg_location ( [ form | t ] ) , do: [ clear_location ( form ) | t ]
818
- def clear_first_arg_location ( [ ] ) , do: [ ]
825
+ defp is_lineless? ( expr ) do
826
+ elem ( expr , 0 ) in @ lineless_forms
827
+ end
819
828
820
- def clear_location ( form ) , do: put_elem ( form , 1 , :erl_anno . set_line ( 0 , elem ( form , 1 ) ) )
829
+ defp clear_location ( form ) , do: put_elem ( form , 1 , :erl_anno . set_line ( 0 , elem ( form , 1 ) ) )
821
830
end
0 commit comments