@@ -4,16 +4,18 @@ defmodule Representer do
44 alias Representer.Mapping
55
66 def process ( file , code_output , mapping_output ) do
7- { represented_ast , mapping } = represent ( file )
7+ { represented_ast , mapping } =
8+ file
9+ |> File . read! ( )
10+ |> represent
811
912 File . write! ( code_output , Macro . to_string ( represented_ast ) <> "\n " )
1013 File . write! ( mapping_output , to_string ( mapping ) )
1114 end
1215
13- def represent ( file ) do
16+ def represent ( code ) do
1417 { ast , mapping } =
15- file
16- |> File . read! ( )
18+ code
1719 |> Code . string_to_quoted! ( )
1820 |> Macro . prewalk ( & add_meta / 1 )
1921 |> Macro . prewalk ( Mapping . init ( ) , & define_placeholders / 2 )
@@ -49,17 +51,23 @@ defmodule Representer do
4951 do_define_placeholders ( node , represented )
5052 end
5153
54+ # module definition
5255 defp do_define_placeholders (
53- { :defmodule , [ line: x ] ,
54- [ { :__aliases__ , [ line: x ] , [ module_name ] } = module_alias | _ ] = args } = node ,
56+ { :defmodule , meta1 , [ { :__aliases__ , meta2 , module_name } , content ] } ,
5557 represented
5658 ) do
57- { :ok , represented , mapped_term } = Mapping . get_placeholder ( represented , module_name , :module )
58-
59- module_alias = module_alias |> Tuple . delete_at ( 2 ) |> Tuple . append ( [ mapped_term ] )
60- args = [ module_alias | args |> tl ]
61- node = node |> Tuple . delete_at ( 2 ) |> Tuple . append ( args )
59+ { :ok , represented , names } = Mapping . get_placeholder ( represented , module_name )
60+ node = { :defmodule , meta1 , [ { :__aliases__ , meta2 , names } , content ] }
61+ { node , represented }
62+ end
6263
64+ # module alias
65+ defp do_define_placeholders (
66+ { :alias , meta , [ module , [ as: { :__aliases__ , meta2 , module_alias } ] ] } ,
67+ represented
68+ ) do
69+ { :ok , represented , names } = Mapping . get_placeholder ( represented , module_alias )
70+ node = { :alias , meta , [ module , [ as: { :__aliases__ , meta2 , names } ] ] }
6371 { node , represented }
6472 end
6573
@@ -73,13 +81,13 @@ defmodule Representer do
7381 # function/macro/guard definition with a guard
7482 [ { name3 , meta3 , args3 } | args2_tail ] = args2
7583
76- { :ok , represented , mapped_name } = Representer. Mapping. get_placeholder ( represented , name3 )
84+ { :ok , represented , mapped_name } = Mapping . get_placeholder ( represented , name3 )
7785 meta2 = Keyword . put ( meta2 , :visited? , true )
7886 meta3 = Keyword . put ( meta3 , :visited? , true )
7987
8088 { [ { name , meta2 , [ { mapped_name , meta3 , args3 } | args2_tail ] } | args_tail ] , represented }
8189 else
82- { :ok , represented , mapped_name } = Representer. Mapping. get_placeholder ( represented , name )
90+ { :ok , represented , mapped_name } = Mapping . get_placeholder ( represented , name )
8391 meta2 = Keyword . put ( meta2 , :visited? , true )
8492
8593 { [ { mapped_name , meta2 , args2 } | args_tail ] , represented }
@@ -92,10 +100,10 @@ defmodule Representer do
92100 # variables
93101 # https://elixir-lang.org/getting-started/meta/quote-and-unquote.html
94102 # "The third element is either a list of arguments for the function call or an atom. When this element is an atom, it means the tuple represents a variable."
95- @ special_var_names [ :__CALLER__ , :__DIR__ , :__ENV__ , :__MODULE__ , :__STACKTRACE__ , :... ]
103+ @ special_var_names [ :__CALLER__ , :__DIR__ , :__ENV__ , :__MODULE__ , :__STACKTRACE__ , :... , :_ ]
96104 defp do_define_placeholders ( { atom , meta , context } , represented )
97105 when is_atom ( atom ) and is_nil ( context ) and atom not in @ special_var_names do
98- { :ok , represented , mapped_term } = Representer. Mapping. get_placeholder ( represented , atom )
106+ { :ok , represented , mapped_term } = Mapping . get_placeholder ( represented , atom )
99107
100108 { { mapped_term , meta , context } , represented }
101109 end
@@ -114,10 +122,23 @@ defmodule Representer do
114122 do_use_existing_placeholders ( node , represented )
115123 end
116124
125+ # module names
126+ defp do_use_existing_placeholders ( { :__aliases__ , meta , module_name } , represented )
127+ when is_list ( module_name ) do
128+ module_name =
129+ Enum . map (
130+ module_name ,
131+ & ( Mapping . get_existing_placeholder ( represented , & 1 ) || & 1 )
132+ )
133+
134+ meta = Keyword . put ( meta , :visited? , true )
135+ { { :__aliases__ , meta , module_name } , represented }
136+ end
137+
117138 # local function calls
118139 defp do_use_existing_placeholders ( { atom , meta , context } , represented )
119140 when is_atom ( atom ) and is_list ( context ) do
120- placeholder = Representer. Mapping. get_existing_placeholder ( represented , atom )
141+ placeholder = Mapping . get_existing_placeholder ( represented , atom )
121142
122143 # if there is no placeholder for this name, that means it's an imported or a standard library function/macro/special form
123144 atom = placeholder || atom
@@ -127,31 +148,30 @@ defmodule Representer do
127148
128149 # external function calls
129150 defp do_use_existing_placeholders (
130- { { :. , meta2 , [ { :__aliases__ , meta3 , [ module_name ] } , function_name ] } , meta , context } ,
151+ { { :. , meta2 , [ { :__aliases__ , _ , module_name } = module , function_name ] } , meta , context } ,
131152 represented
132153 )
133- when is_atom ( module_name ) and is_atom ( function_name ) do
134- placeholder_module_name =
135- Representer.Mapping . get_existing_placeholder ( represented , module_name )
154+ when is_list ( module_name ) and is_atom ( function_name ) do
155+ { { _ , _ , new_module_name } = module , _ } = do_use_existing_placeholders ( module , represented )
136156
137- module_name = placeholder_module_name || module_name
157+ all_replaced? =
158+ Enum . zip_with ( module_name , new_module_name , & ( & 1 != & 2 ) )
159+ |> Enum . all? ( )
138160
139161 placeholder_function_name =
140- if placeholder_module_name do
141- Representer. Mapping. get_existing_placeholder ( represented , function_name )
162+ if all_replaced? do
163+ Mapping . get_existing_placeholder ( represented , function_name )
142164 else
143- # hack: assuming that if a module has no placeholder name, that means it's not being defined in this file
165+ # hack: assuming that if a module has no complete placeholder name, that means it's not being defined in this file
144166 # TODO: fix when dealing with aliases
145167 nil
146168 end
147169
148170 function_name = placeholder_function_name || function_name
149171
150172 meta2 = Keyword . put ( meta2 , :visited? , true )
151- meta3 = Keyword . put ( meta3 , :visited? , true )
152173
153- { { { :. , meta2 , [ { :__aliases__ , meta3 , [ module_name ] } , function_name ] } , meta , context } ,
154- represented }
174+ { { { :. , meta2 , [ module , function_name ] } , meta , context } , represented }
155175 end
156176
157177 # external function calls via __MODULE__
@@ -160,8 +180,7 @@ defmodule Representer do
160180 represented
161181 )
162182 when is_atom ( function_name ) do
163- placeholder_function_name =
164- Representer.Mapping . get_existing_placeholder ( represented , function_name )
183+ placeholder_function_name = Mapping . get_existing_placeholder ( represented , function_name )
165184
166185 function_name = placeholder_function_name || function_name
167186 meta2 = Keyword . put ( meta2 , :visited? , true )
0 commit comments