@@ -4,6 +4,7 @@ defmodule Dx.Defd.Compiler do
44 alias Dx.Defd.Ast
55 alias Dx.Defd.Ast.Loader
66 alias Dx.Defd.Ast.State
7+ alias Dx.Defd.NonDx
78 alias Dx.Defd.Util
89
910 import Ast.Guards
@@ -23,24 +24,24 @@ defmodule Dx.Defd.Compiler do
2324 defds = compile_prepare_arities ( exports )
2425 all_arities = all_arities ( exports )
2526
26- state = % {
27- module: module ,
28- file: file ,
29- line: line ,
30- function: nil ,
31- defds: defds ,
32- all_arities: all_arities ,
33- used_defds: MapSet . new ( ) ,
34- args : MapSet . new ( ) ,
35- var_index: 1 ,
36- scope_args: [ ] ,
37- eval_var: eval_var ,
38- warn_non_dx?: true ,
39- called_non_dx?: false ,
40- loaders: [ ] ,
41- finalized_vars: MapSet . new ( ) ,
42- rewrite_underscore?: false
43- }
27+ state =
28+ % {
29+ module: module ,
30+ file: file ,
31+ line: line ,
32+ function: nil ,
33+ defds: defds ,
34+ all_arities: all_arities ,
35+ used_defds : MapSet . new ( ) ,
36+ args: MapSet . new ( ) ,
37+ var_index: 1 ,
38+ scope_args: [ ] ,
39+ eval_var: eval_var ,
40+ loaders: [ ] ,
41+ finalized_vars: MapSet . new ( ) ,
42+ rewrite_underscore?: false
43+ }
44+ |> NonDx . init ( )
4445
4546 { quoted , state } =
4647 Enum . flat_map_reduce ( exports , state , fn def , state ->
@@ -307,15 +308,17 @@ defmodule Dx.Defd.Compiler do
307308 case_ast = { :case , [ line: line ] , [ case_subject , [ do: case_clauses ] ] }
308309
309310 { final_args_ast , final_args_state } =
310- State . pass_in (
311- state ,
312- [ warn_non_dx?: false , finalized_vars: & Ast . collect_vars ( state . all_args , & 1 ) ] ,
313- fn state ->
314- Ast . with_root_args ( state . all_args , state , fn state ->
315- Dx.Defd.Case . normalize ( case_ast , state )
316- end )
317- end
318- )
311+ NonDx . suppress_warnings ( state , fn state ->
312+ State . pass_in (
313+ state ,
314+ [ finalized_vars: & Ast . collect_vars ( state . all_args , & 1 ) ] ,
315+ fn state ->
316+ Ast . with_root_args ( state . all_args , state , fn state ->
317+ Dx.Defd.Case . normalize ( case_ast , state )
318+ end )
319+ end
320+ )
321+ end )
319322
320323 { { final_args_args , final_args_ast } , final_args_state } =
321324 maybe_unwrap_case ( final_args_ast , final_args_state )
@@ -483,20 +486,8 @@ defmodule Dx.Defd.Compiler do
483486 |> with_state ( state )
484487 end
485488
486- def normalize ( { { :. , meta , [ Dx.Defd , :non_dx ] } , _meta2 , [ ast ] } , orig_state ) do
487- State . pass_in ( orig_state , [ warn_non_dx?: false , called_non_dx?: false ] , fn state ->
488- { ast , state } = normalize ( ast , state )
489-
490- if orig_state . warn_non_dx? and not state . called_non_dx? do
491- warn ( meta , state , """
492- No function was called that is not defined with defd.
493-
494- Please remove the call to non_dx/1.
495- """ )
496- end
497-
498- { ast , state }
499- end )
489+ def normalize ( { { :. , _meta , [ Dx.Defd , :non_dx ] } , _meta2 , [ _ast ] } = ast , orig_state ) do
490+ NonDx . normalize ( ast , orig_state )
500491 end
501492
502493 def normalize ( { :fn , _meta , clauses } = fun , state ) when is_list ( clauses ) do
@@ -577,7 +568,7 @@ defmodule Dx.Defd.Compiler do
577568 end
578569
579570 # &local_fun/2
580- def normalize ( { :& , meta , [ { :/ , [ ] , [ { fun_name , meta2 , nil } , arity ] } ] } , state ) do
571+ def normalize ( { :& , meta , [ { :/ , [ ] , [ { fun_name , meta2 , nil } , arity ] } ] } = fun , state ) do
581572 args = Macro . generate_arguments ( arity , __MODULE__ )
582573 line = meta [ :line ] || state . line
583574
@@ -605,23 +596,7 @@ defmodule Dx.Defd.Compiler do
605596 ] } }
606597 |> with_state ( state )
607598 else
608- if state . warn_non_dx? do
609- warn ( meta , state , """
610- #{ fun_name } /#{ arity } is not defined with defd.
611-
612- Either define it using defd (preferred) or wrap the call in the non_dx/1 function:
613-
614- non_dx(...(&#{ fun_name } /#{ arity } ))
615- """ )
616- end
617-
618- quote line: line do
619- { :ok ,
620- fn unquote_splicing ( args ) ->
621- { :ok , unquote ( fun_name ) ( unquote_splicing ( args ) ) }
622- end }
623- end
624- |> with_state ( % { state | called_non_dx?: true } )
599+ NonDx . normalize ( fun , state )
625600 end
626601 end
627602
@@ -672,23 +647,7 @@ defmodule Dx.Defd.Compiler do
672647 |> with_state ( state )
673648
674649 true ->
675- if state . warn_non_dx? do
676- warn ( meta , state , """
677- #{ fun_name } /#{ arity } is not defined with defd.
678-
679- Either define it using defd (preferred) or wrap the call in the non_dx/1 function:
680-
681- non_dx(...(&#{ module } .#{ fun_name } /#{ arity } ))
682- """ )
683- end
684-
685- quote line: line do
686- { :ok ,
687- fn unquote_splicing ( args ) ->
688- { :ok , unquote ( module ) . unquote ( fun_name ) ( unquote_splicing ( args ) ) }
689- end }
690- end
691- |> with_state ( % { state | called_non_dx?: true } )
650+ NonDx . normalize ( fun , state )
692651 end
693652 end
694653
@@ -697,37 +656,17 @@ defmodule Dx.Defd.Compiler do
697656 when is_atom ( fun_name ) and is_list ( args ) do
698657 arity = length ( args )
699658
700- cond do
701- { fun_name , arity } in state . defds ->
702- defd_name = Util . defd_name ( fun_name )
703-
704- state = Map . update! ( state , :used_defds , & MapSet . put ( & 1 , { fun_name , arity } ) )
705-
706- normalize_call_args ( args , state , fn args ->
707- { defd_name , meta , args ++ [ state . eval_var ] }
708- end )
709- |> Loader . add ( )
710-
711- Util . has_function? ( state . module , fun_name , arity ) ->
712- if state . warn_non_dx? do
713- warn ( meta , state , """
714- #{ fun_name } /#{ arity } is not defined with defd.
715-
716- Either define it using defd (preferred) or wrap the call in the non_dx/1 function:
717-
718- non_dx(#{ fun_name } (...))
719- """ )
720- end
721-
722- { ast , state } =
723- normalize_external_call_args ( args , state , fn args ->
724- { fun_name , meta , args }
725- end )
659+ if { fun_name , arity } in state . defds do
660+ defd_name = Util . defd_name ( fun_name )
726661
727- { { :ok , ast } , % { state | called_non_dx?: true } }
662+ state = Map . update! ( state , :used_defds , & MapSet . put ( & 1 , { fun_name , arity } ) )
728663
729- true ->
730- { { :ok , fun } , state }
664+ normalize_call_args ( args , state , fn args ->
665+ { defd_name , meta , args ++ [ state . eval_var ] }
666+ end )
667+ |> Loader . add ( )
668+ else
669+ NonDx . normalize ( fun , state )
731670 end
732671 end
733672
@@ -774,38 +713,8 @@ defmodule Dx.Defd.Compiler do
774713 end )
775714 |> Loader . add ( )
776715
777- # avoid non_dx warning for `Dx.Scope.all/1`
778- { module , fun_name , arity } == { Dx.Scope , :all , 1 } ->
779- normalize_external_call_args ( args , state , fn args ->
780- { { :. , meta , [ module , fun_name ] } , meta2 , args }
781- end )
782- |> Ast . ok ( )
783-
784- Util . has_function? ( module , fun_name , arity ) ->
785- if state . warn_non_dx? do
786- warn ( meta2 , state , """
787- #{ inspect ( module ) } .#{ fun_name } /#{ arity } is not defined with defd.
788-
789- Either define it using defd (preferred) or wrap the call in the non_dx/1 function:
790-
791- non_dx(#{ inspect ( module ) } .#{ fun_name } (...))
792- """ )
793- end
794-
795- { ast , state } =
796- normalize_external_call_args ( args , state , fn args ->
797- { { :. , meta , [ module , fun_name ] } , meta2 , args }
798- end )
799-
800- { { :ok , ast } , % { state | called_non_dx?: true } }
801-
802716 true ->
803- { ast , state } =
804- normalize_external_call_args ( args , state , fn args ->
805- { { :. , meta , [ module , fun_name ] } , meta2 , args }
806- end )
807-
808- { { :ok , ast } , state }
717+ NonDx . normalize ( fun , state )
809718 end
810719 end
811720
@@ -902,115 +811,12 @@ defmodule Dx.Defd.Compiler do
902811 :error
903812 end
904813
905- # extracts only loaders based on variables bound outside of the external anonymous function
906- defp normalize_external_fn ( ast , state ) do
907- Macro . prewalk ( ast , state , fn
908- { { :. , _meta , [ _module , fun_name ] } , meta2 , args } = fun , state
909- when is_atom ( fun_name ) and is_list ( args ) ->
910- # Access.get/2
911- if meta2 [ :no_parens ] do
912- case maybe_capture_loader ( fun , state ) do
913- { :ok , _loader_ast , state } ->
914- subject = root_var_from_access_chain ( fun )
915- data_req = data_req_from_access_chain ( fun , % { } )
916-
917- { { :ok , var } , state } =
918- quote do
919- Dx.Defd.Runtime . fetch (
920- unquote ( subject ) ,
921- unquote ( Macro . escape ( data_req ) ) ,
922- unquote ( state . eval_var )
923- )
924- end
925- |> Loader . add ( state )
926-
927- replace_root_var ( fun , var )
928- |> with_state ( state )
929-
930- :error ->
931- { fun , state }
932- end
933- else
934- { fun , state }
935- end
936-
937- ast , state ->
938- { ast , state }
939- end )
940- end
941-
942- def root_var_from_access_chain ( { { :. , _meta , [ ast , _fun_name ] } , _meta2 , [ ] } ) do
943- root_var_from_access_chain ( ast )
944- end
945-
946- def root_var_from_access_chain ( var ) when is_var ( var ) do
947- var
948- end
949-
950- def replace_root_var ( { { :. , meta , [ ast , fun_name ] } , meta2 , [ ] } , new_var ) do
951- { { :. , meta , [ replace_root_var ( ast , new_var ) , fun_name ] } , meta2 , [ ] }
952- end
953-
954- def replace_root_var ( var , new_var ) when is_var ( var ) do
955- new_var
956- end
957-
958- def data_req_from_access_chain ( { { :. , _meta , [ ast , fun_name ] } , _meta2 , [ ] } , acc ) do
959- acc = % { fun_name => acc }
960- data_req_from_access_chain ( ast , acc )
961- end
962-
963- def data_req_from_access_chain ( var , acc ) when is_var ( var ) do
964- acc
965- end
966-
967- def normalize_external_call_args ( args , state , fun ) do
968- { args , new_state } =
969- Enum . map_reduce ( args , state , fn
970- { :fn , meta , [ { :-> , meta2 , [ args , body ] } ] } , state ->
971- { body , new_state } = normalize_external_fn ( body , state )
972-
973- { :ok , { :fn , meta , [ { :-> , meta2 , [ args , body ] } ] } }
974- |> with_state ( new_state )
975-
976- { :& , _meta , [ { :/ , [ ] , [ { { :. , _meta2 , [ _mod , _fun_name ] } , _meta3 , [ ] } , _arity ] } ] } = fun ,
977- state ->
978- { { :ok , fun } , state }
979-
980- { :& , _meta , [ { :/ , [ ] , [ { _fun_name , _meta2 , nil } , _arity ] } ] } = fun , state ->
981- { { :ok , fun } , state }
982-
983- arg , state ->
984- normalize ( arg , state )
985- end )
986-
987- { args , new_state } = args |> Enum . map ( & Ast . unwrap / 1 ) |> finalize_args ( new_state )
988-
989- do_normalize_call_args ( args , new_state , fun )
990- end
991-
992- def finalize_args ( args , state ) do
993- Enum . map_reduce ( args , state , fn arg , state ->
994- vars = Ast . collect_vars ( arg )
995-
996- if MapSet . subset? ( vars , state . finalized_vars ) do
997- { :ok , arg }
998- |> with_state ( state )
999- else
1000- quote do
1001- Dx.Defd.Runtime . finalize ( unquote ( arg ) , unquote ( state . eval_var ) )
1002- end
1003- |> Loader . add ( state )
1004- end
1005- end )
1006- end
1007-
1008814 def normalize_call_args ( args , state , fun ) do
1009815 { args , state } = Enum . map_reduce ( args , state , & normalize / 2 )
1010816 do_normalize_call_args ( args , state , fun )
1011817 end
1012818
1013- defp do_normalize_call_args ( args , state , fun ) do
819+ def do_normalize_call_args ( args , state , fun ) do
1014820 args
1015821 |> Enum . map ( & Ast . unwrap / 1 )
1016822 |> fun . ( )
0 commit comments