@@ -4,10 +4,11 @@ defmodule Refactorex.Refactor.Function.ExtractAnonymousFunction do
44 kind: "refactor.extract" ,
55 works_on: :selection
66
7+ alias Refactorex.Dataflow
8+
79 alias Refactorex.Refactor . {
810 Function ,
9- Module ,
10- Variable
11+ Module
1112 }
1213
1314 @ function_name "extracted_function"
@@ -33,71 +34,34 @@ defmodule Refactorex.Refactor.Function.ExtractAnonymousFunction do
3334 end
3435 end
3536
36- def refactor ( % { node: { :& , _ , [ body ] } } = zipper , _ ) do
37- closure_variables = Variable . list_unique_variables ( body )
38-
39- # find &{i} usages and replace them with arg{i}
40- { % { node: body } , args } =
41- body
42- |> Z . zip ( )
43- |> Z . traverse_while ( MapSet . new ( ) , fn
44- % { node: { :& , _ , [ i ] } } = zipper , args when is_number ( i ) ->
45- arg = { String . to_atom ( "arg#{ i } " ) , [ ] , nil }
46- { :cont , Z . update ( zipper , fn _ -> arg end ) , MapSet . put ( args , arg ) }
47-
48- zipper , args ->
49- { :cont , zipper , args }
50- end )
51- |> then ( fn { zipper , args } -> { zipper , Enum . into ( args , [ ] ) } end )
52-
53- name = Function . next_available_function_name ( zipper , @ function_name )
54-
37+ def refactor ( % { node: { :& , _ , _ } } = zipper , _ ) do
5538 zipper
56- |> anonymous_to_function_call ( name , args , closure_variables )
57- |> Function . new_private_function ( name , args ++ closure_variables , body )
39+ |> Function.ExpandAnonymousFunction . refactor ( nil )
40+ |> refactor ( nil )
5841 end
5942
60- def refactor ( % { node: { :fn , _ , clauses } } = zipper , _ ) do
61- available_variables = Variable . find_available_variables ( zipper )
62-
63- closure_variables =
64- clauses
65- |> Enum . map ( fn { :-> , _ , [ args , _ ] = clause } ->
66- unpinned_args = Variable . list_unpinned_variables ( args )
67-
68- Variable . list_variables (
69- clause ,
70- & ( Variable . member? ( available_variables , & 1 . node ) and
71- not Variable . member? ( unpinned_args , & 1 . node ) )
72- )
73- end )
74- |> List . flatten ( )
75- |> Variable . remove_duplicates ( )
76-
77- # all clauses have the same number of args,
78- # so we can just grab them from the first one
79- { :-> , _ , [ args , _ ] } = List . first ( clauses )
43+ def refactor ( % { node: { :fn , _ , clauses } = node } = zipper , _ ) do
44+ [ { :-> , _ , [ args , _ ] } | _ ] = clauses
45+
8046 name = Function . next_available_function_name ( zipper , @ function_name )
47+ outer_variables = Dataflow . outer_variables ( node )
48+
49+ args = for i <- 1 .. length ( args ) , do: { :& , [ ] , [ i ] }
50+ args = args ++ outer_variables
8151
8252 zipper
83- |> anonymous_to_function_call ( name , args , closure_variables )
84- |> then (
85- & Enum . reduce ( clauses , & 1 , fn { :-> , _ , [ args , body ] } , zipper ->
86- Function . new_private_function ( zipper , name , args ++ closure_variables , body )
87- end )
88- )
53+ |> Z . replace ( { :& , [ ] , [ { name , [ ] , args } ] } )
54+ |> add_private_functions ( clauses , name , outer_variables )
8955 end
9056
91- defp anonymous_to_function_call ( zipper , name , args , closure_variables ) do
92- Z . update ( zipper , fn _ ->
93- { :& , [ ] ,
94- [
95- { name , [ ] ,
96- 1 .. length ( args )
97- |> Enum . map ( & { :& , [ ] , [ & 1 ] } )
98- |> Kernel . ++ ( closure_variables ) }
99- ] }
100- end )
57+ defp add_private_functions ( zipper , clauses , name , outer_variables ) do
58+ Enum . reduce (
59+ clauses ,
60+ zipper ,
61+ fn { :-> , _ , [ args , body ] } , zipper ->
62+ Function . new_private_function ( zipper , name , args ++ outer_variables , body )
63+ end
64+ )
10165 end
10266
10367 defp already_extracted_function? ( { _ , _ , [ { name , _ , _ } | _ ] } )
0 commit comments