@@ -111,7 +111,7 @@ build(Line, File, Module, Lexical) ->
111111 _ -> ets :insert (DataTable , {on_definition , []})
112112 end ,
113113
114- Attributes = [behaviour , on_load , spec , type , typep , opaque , callback , compile ],
114+ Attributes = [behaviour , on_load , spec , type , typep , opaque , callback , compile , external_resource ],
115115 ets :insert (DataTable , {? acc_attr , [before_compile , after_compile , on_definition , derive |Attributes ]}),
116116 ets :insert (DataTable , {? persisted_attr , [vsn |Attributes ]}),
117117 ets :insert (DataTable , {? docs_attr , ets :new (DataTable , [ordered_set , public ])}),
@@ -156,7 +156,7 @@ functions_form(Line, File, Module, BaseAll, BaseExport, Def, Defmacro, BaseFunct
156156
157157% % Add attributes handling to the form
158158
159- attributes_form (Line , _File , Module , Current ) ->
159+ attributes_form (Line , File , Module , Current ) ->
160160 Table = data_table (Module ),
161161
162162 AccAttrs = ets :lookup_element (Table , '__acc_attributes' , 2 ),
@@ -166,16 +166,31 @@ attributes_form(Line, _File, Module, Current) ->
166166 case lists :member (Key , PersistedAttrs ) of
167167 false -> Acc ;
168168 true ->
169- Attrs = case lists :member (Key , AccAttrs ) of
170- true -> Value ;
171- false -> [Value ]
172- end ,
173- lists :foldl (fun (X , Final ) -> [{attribute , Line , Key , X }|Final ] end , Acc , Attrs )
169+ Values =
170+ case lists :member (Key , AccAttrs ) of
171+ true -> Value ;
172+ false -> [Value ]
173+ end ,
174+
175+ lists :foldl (fun (X , Final ) ->
176+ [{attribute , Line , Key , X }|Final ]
177+ end , Acc , process_attribute (Line , File , Key , Values ))
174178 end
175179 end ,
176180
177181 ets :foldl (Transform , Current , Table ).
178182
183+ process_attribute (Line , File , external_resource , Values ) ->
184+ lists :usort ([process_external_resource (Line , File , Value ) || Value <- Values ]);
185+ process_attribute (_Line , _File , _Key , Values ) ->
186+ Values .
187+
188+ process_external_resource (_Line , _File , Value ) when is_binary (Value ) ->
189+ Value ;
190+ process_external_resource (Line , File , Value ) ->
191+ elixir_errors :handle_file_error (File ,
192+ {Line , ? MODULE , {invalid_external_resource , Value }}).
193+
179194% % Types
180195
181196types_form (Module , Forms0 ) ->
@@ -463,14 +478,17 @@ prune_stacktrace(Info, []) ->
463478
464479format_error ({invalid_clause , {Name , Arity }}) ->
465480 io_lib :format (" empty clause provided for nonexistent function or macro ~ts /~B " , [Name , Arity ]);
481+ format_error ({invalid_external_resource , Value }) ->
482+ io_lib :format (" expected a string value for @external_resource, got: ~p " ,
483+ ['Elixir.Kernel' :inspect (Value )]);
466484format_error ({unused_doc , typedoc }) ->
467485 " @typedoc provided but no type follows it" ;
468486format_error ({unused_doc , doc }) ->
469487 " @doc provided but no definition follows it" ;
470488format_error ({internal_function_overridden , {Name , Arity }}) ->
471489 io_lib :format (" function ~ts /~B is internal and should not be overridden" , [Name , Arity ]);
472490format_error ({invalid_module , Module }) ->
473- io_lib :format (" invalid module name: ~p " , [Module ]);
491+ io_lib :format (" invalid module name: ~ts " , ['Elixir.Kernel' : inspect ( Module ) ]);
474492format_error ({module_defined , Module }) ->
475493 io_lib :format (" redefining module ~ts " , [elixir_aliases :inspect (Module )]);
476494format_error ({module_reserved , Module }) ->
0 commit comments