Skip to content

Commit 3f7b867

Browse files
author
José Valim
committed
Refactor elixir_dispatch to rely more on elixir_scope
1 parent f2e78d3 commit 3f7b867

File tree

5 files changed

+71
-60
lines changed

5 files changed

+71
-60
lines changed

lib/elixir/lib/macro.ex

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -502,13 +502,15 @@ defmodule Macro do
502502
end
503503
504504
"""
505-
def expand(aliases, env)
505+
def expand(aliases, env) do
506+
expand(aliases, env, nil)
507+
end
506508

507-
def expand({ :__aliases__, _, _ } = original, env) do
509+
defp expand({ :__aliases__, _, _ } = original, env, cache) do
508510
case :elixir_aliases.expand(original, env.aliases, []) do
509511
atom when is_atom(atom) -> atom
510512
aliases ->
511-
aliases = lc alias inlist aliases, do: expand(alias, env)
513+
aliases = lc alias inlist aliases, do: expand(alias, env, cache)
512514

513515
case :lists.all(is_atom(&1), aliases) do
514516
true -> :elixir_aliases.concat(aliases)
@@ -518,20 +520,20 @@ defmodule Macro do
518520
end
519521

520522
# Expand @ calls
521-
def expand({ :@, _, [{ name, _, args }] } = original, env) when is_atom(args) or args == [] do
523+
defp expand({ :@, _, [{ name, _, args }] } = original, env, _cache) when is_atom(args) or args == [] do
522524
case (module = env.module) && Module.open?(module) do
523525
true -> Module.get_attribute(module, name)
524526
false -> original
525527
end
526528
end
527529

528530
# Expand pseudo-variables
529-
def expand({ :__MODULE__, _, atom }, env) when is_atom(atom), do: env.module
530-
def expand({ :__FILE__, _, atom }, env) when is_atom(atom), do: env.file
531-
def expand({ :__ENV__, _, atom }, env) when is_atom(atom), do: env
531+
defp expand({ :__MODULE__, _, atom }, env, _cache) when is_atom(atom), do: env.module
532+
defp expand({ :__FILE__, _, atom }, env, _cache) when is_atom(atom), do: env.file
533+
defp expand({ :__ENV__, _, atom }, env, _cache) when is_atom(atom), do: env
532534

533535
# Expand possible macro import invocation
534-
def expand({ atom, line, args } = original, env) when is_atom(atom) do
536+
defp expand({ atom, line, args } = original, env, cache) when is_atom(atom) do
535537
args = case is_atom(args) do
536538
true -> []
537539
false -> args
@@ -549,7 +551,7 @@ defmodule Macro do
549551
end
550552

551553
expand = :elixir_dispatch.expand_import(line, { atom, length(args) }, args,
552-
env.module, env.function, env.requires, env.functions, extra ++ env.macros, env)
554+
env.module, extra, to_erl_env(env, cache))
553555
case expand do
554556
{ :ok, _, expanded } -> expanded
555557
{ :error, _ } -> original
@@ -558,14 +560,14 @@ defmodule Macro do
558560
end
559561

560562
# Expand possible macro require invocation
561-
def expand({ { :., _, [left, right] }, line, args } = original, env) when is_atom(right) do
563+
defp expand({ { :., _, [left, right] }, line, args } = original, env, cache) when is_atom(right) do
562564
receiver = expand(left, env)
563565

564566
case is_atom(receiver) and not is_partial?(args) do
565567
false -> original
566568
true ->
567569
expand = :elixir_dispatch.expand_require(line, receiver, { right, length(args) },
568-
args, env.module, env.function, env.requires, env)
570+
args, env.module, to_erl_env(env, cache))
569571
case expand do
570572
{ :ok, expanded } -> expanded
571573
{ :error, _ } -> original
@@ -574,7 +576,10 @@ defmodule Macro do
574576
end
575577

576578
# Anything else is just returned
577-
def expand(other, _env), do: other
579+
defp expand(other, _env, _cache), do: other
580+
581+
defp to_erl_env(env, nil), do: :elixir_scope.to_erl_env(env)
582+
defp to_erl_env(_env, cache), do: cache
578583

579584
## Helpers
580585

lib/elixir/src/elixir_dispatch.erl

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
-export([default_macros/0, default_functions/0, default_requires/0,
66
dispatch_require/6, dispatch_import/5,
77
require_function/5, import_function/4,
8-
expand_import/9, expand_require/8, find_import/4,
8+
expand_import/6, expand_require/6, find_import/4,
99
format_error/1, in_erlang_functions/0, in_erlang_macros/0]).
1010
-include("elixir.hrl").
1111
-compile({parse_transform, elixir_transform}).
@@ -23,7 +23,7 @@ default_requires() ->
2323
find_import(Meta, Name, Arity, S) ->
2424
Tuple = { Name, Arity },
2525

26-
case find_dispatch(Meta, Tuple, S#elixir_scope.functions, S#elixir_scope.macros, S#elixir_scope.file) of
26+
case find_dispatch(Meta, Tuple, S) of
2727
{ function, Receiver } -> Receiver;
2828
{ macro, Receiver } -> Receiver;
2929
nomatch -> false
@@ -33,7 +33,7 @@ find_import(Meta, Name, Arity, S) ->
3333

3434
import_function(Meta, Name, Arity, S) ->
3535
Tuple = { Name, Arity },
36-
case find_dispatch(Meta, Tuple, S#elixir_scope.functions, S#elixir_scope.macros, S#elixir_scope.file) of
36+
case find_dispatch(Meta, Tuple, S) of
3737
{ function, Receiver } ->
3838
elixir_import:record(import, Tuple, Receiver, S#elixir_scope.module),
3939
remote_function(Meta, Receiver, Name, Arity, S);
@@ -58,7 +58,7 @@ dispatch_import(Meta, Name, Args, S, Callback) ->
5858
Arity = length(Args),
5959
Tuple = { Name, Arity },
6060

61-
case find_dispatch(Meta, Tuple, S#elixir_scope.functions, S#elixir_scope.macros, S#elixir_scope.file) of
61+
case find_dispatch(Meta, Tuple, S) of
6262
{ function, Receiver } ->
6363
elixir_import:record(import, Tuple, Receiver, Module),
6464
Endpoint = case (Receiver == ?BUILTIN) andalso is_element(Tuple, in_erlang_functions()) of
@@ -67,8 +67,7 @@ dispatch_import(Meta, Name, Args, S, Callback) ->
6767
end,
6868
elixir_translator:translate_each({ { '.', Meta, [Endpoint, Name] }, Meta, Args }, S);
6969
Result ->
70-
case expand_import(Meta, Tuple, Args, Module, S#elixir_scope.function,
71-
S#elixir_scope.requires, S, Result) of
70+
case do_expand_import(Meta, Tuple, Args, Module, S, Result) of
7271
{ error, noexpansion } ->
7372
Callback();
7473
{ error, internal } ->
@@ -88,8 +87,7 @@ dispatch_require(Meta, Receiver, Name, Args, S, Callback) ->
8887
true ->
8988
elixir_translator:translate_each({ { '.', Meta, [erlang, Name] }, Meta, Args }, S);
9089
false ->
91-
case expand_require(Meta, Receiver, Tuple, Args, Module,
92-
S#elixir_scope.function, S#elixir_scope.requires, S) of
90+
case expand_require(Meta, Receiver, Tuple, Args, Module, S) of
9391
{ error, noexpansion } ->
9492
Callback();
9593
{ error, internal } ->
@@ -101,84 +99,85 @@ dispatch_require(Meta, Receiver, Name, Args, S, Callback) ->
10199

102100
%% Macros expansion
103101

104-
expand_import(Meta, { Name, Arity } = Tuple, Args, Module, Function, Requires, SEnv, Result) ->
102+
expand_import(Meta, Tuple, Args, Module, Extra, S) ->
103+
Result = find_dispatch(Meta, Tuple, Extra, S),
104+
do_expand_import(Meta, Tuple, Args, Module, S, Result).
105+
106+
do_expand_import(Meta, { Name, Arity } = Tuple, Args, Module, S, Result) ->
105107
case Result of
106108
{ macro, ?BUILTIN } ->
107109
case is_element(Tuple, in_erlang_macros()) of
108110
true -> { error, internal };
109111
false ->
110112
elixir_import:record(import, Tuple, ?BUILTIN, Module),
111-
{ ok, ?BUILTIN, expand_macro_named(Meta, ?BUILTIN, Name, Arity, Args, Module, Requires, SEnv) }
113+
{ ok, ?BUILTIN, expand_macro_named(Meta, ?BUILTIN, Name, Arity, Args, Module, S) }
112114
end;
113115
{ macro, Receiver } ->
114116
elixir_import:record(import, Tuple, Receiver, Module),
115-
{ ok, Receiver, expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, Requires, SEnv) };
117+
{ ok, Receiver, expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, S) };
116118
_ ->
117-
Fun = (Function /= Tuple) andalso
119+
Fun = (S#elixir_scope.function /= Tuple) andalso
118120
elixir_def_local:macro_for(Tuple, true, Module),
119121
case Fun of
120122
false -> { error, noexpansion };
121123
_ ->
122124
elixir_import:record(import, Tuple, Module, Module),
123-
{ ok, Module, expand_macro_fun(Meta, Fun, Module, Name, Args, Module, Requires, SEnv) }
125+
{ ok, Module, expand_macro_fun(Meta, Fun, Module, Name, Args, Module, S) }
124126
end
125127
end.
126128

127-
expand_import(Meta, Tuple, Args, Module, Function, Requires, Functions, Macros, SEnv) ->
128-
Result = find_dispatch(Meta, Tuple, Functions, Macros, elixir_scope:filename(SEnv)),
129-
expand_import(Meta, Tuple, Args, Module, Function, Requires, SEnv, Result).
130-
131-
expand_require(Meta, ?BUILTIN, { Name, Arity } = Tuple, Args, Module, _Function, Requires, SEnv) ->
129+
expand_require(Meta, ?BUILTIN, { Name, Arity } = Tuple, Args, Module, S) ->
132130
case is_element(Tuple, in_erlang_macros()) of
133131
true -> { error, internal };
134132
false ->
135133
case is_element(Tuple, in_elixir_macros()) of
136-
true -> { ok, expand_macro_named(Meta, ?BUILTIN, Name, Arity, Args, Module, Requires, SEnv) };
134+
true -> { ok, expand_macro_named(Meta, ?BUILTIN, Name, Arity, Args, Module, S) };
137135
false -> { error, noexpansion }
138136
end
139137
end;
140138

141-
expand_require(Meta, Receiver, { Name, Arity } = Tuple, Args, Module, Function, Requires, SEnv) ->
142-
Fun = (Module == Receiver) andalso (Function /= Tuple) andalso
139+
expand_require(Meta, Receiver, { Name, Arity } = Tuple, Args, Module, S) ->
140+
Fun = (Module == Receiver) andalso (S#elixir_scope.function /= Tuple) andalso
143141
elixir_def_local:macro_for(Tuple, false, Module),
144142

145143
case Fun of
146144
false ->
147145
case is_element(Tuple, get_optional_macros(Receiver)) of
148-
true -> { ok, expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, Requires, SEnv) };
146+
true -> { ok, expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, S) };
149147
false -> { error, noexpansion }
150148
end;
151149
_ ->
152150
elixir_import:record(import, Tuple, Receiver, Module),
153-
{ ok, expand_macro_fun(Meta, Fun, Receiver, Name, Args, Module, Requires, SEnv) }
151+
{ ok, expand_macro_fun(Meta, Fun, Receiver, Name, Args, Module, S) }
154152
end.
155153

156154
%% Expansion helpers
157155

158-
expand_macro_fun(Meta, Fun, Receiver, Name, Args, Module, Requires, SEnv) ->
159-
case (Receiver == Module) or is_element(Receiver, Requires) or skip_requires(SEnv) of
156+
expand_macro_fun(Meta, Fun, Receiver, Name, Args, Module, S) ->
157+
Requires = S#elixir_scope.requires,
158+
case (Receiver == Module) or is_element(Receiver, Requires) or not(S#elixir_scope.check_requires) of
160159
true -> ok;
161160
false ->
162161
Tuple = { unrequired_module, { Receiver, Name, length(Args), Requires } },
163-
elixir_errors:form_error(Meta, elixir_scope:filename(SEnv), ?MODULE, Tuple)
162+
elixir_errors:form_error(Meta, S#elixir_scope.file, ?MODULE, Tuple)
164163
end,
165164

166165
Line = ?line(Meta),
167-
SArg = {Line,SEnv},
166+
SArg = {Line,S},
168167

169168
try
170169
apply(Fun, [SArg|Args])
171170
catch
172171
Kind:Reason ->
173-
Info = { Receiver, Name, length(Args), [{ file, elixir_scope:filename(SEnv) }, { line, Line }] },
172+
Info = { Receiver, Name, length(Args), [{ file, S#elixir_scope.file }, { line, Line }] },
174173
erlang:raise(Kind, Reason, munge_stacktrace(Info, erlang:get_stacktrace(), SArg))
175174
end.
176175

177-
expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, Requires, SEnv) ->
176+
expand_macro_named(Meta, Receiver, Name, Arity, Args, Module, S) ->
178177
ProperName = ?elixir_macro(Name),
179178
ProperArity = Arity + 1,
180179
Fun = fun Receiver:ProperName/ProperArity,
181-
expand_macro_fun(Meta, Fun, Receiver, Name, Args, Module, Requires, SEnv).
180+
expand_macro_fun(Meta, Fun, Receiver, Name, Args, Module, S).
182181

183182
translate_expansion(Meta, Tree, S) ->
184183
{ TR, TS } = elixir_translator:translate_each(
@@ -197,10 +196,20 @@ merge_aliases(A1, A2) ->
197196

198197
%% Helpers
199198

200-
skip_requires(#elixir_scope{check_requires=false}) -> true;
201-
skip_requires(_) -> false.
199+
% case lists:keyfind(import, 1, Meta) of
200+
% { import, Receiver } ->
201+
% { TRes, TS } = translate_each({ { '.', Meta, [Receiver, Atom] }, Meta, Args },
202+
% S#elixir_scope{check_requires=false}),
203+
% { TRes, TS#elixir_scope{check_requires=S#elixir_scope.check_requires} };
204+
% false ->
205+
206+
find_dispatch(Meta, Tuple, S) ->
207+
find_dispatch(Meta, Tuple, [], S).
202208

203-
find_dispatch(Meta, Tuple, Functions, Macros, File) ->
209+
find_dispatch(Meta, Tuple, Extra, S) ->
210+
Functions = S#elixir_scope.functions,
211+
Macros = Extra ++ S#elixir_scope.macros,
212+
File = S#elixir_scope.file,
204213
FunMatch = find_dispatch(Tuple, Functions),
205214
MacMatch = find_dispatch(Tuple, Macros),
206215

lib/elixir/src/elixir_macros.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ translate({ function, Meta, [[{do,{ '->',_,Pairs}}]] }, S) ->
5656
assert_no_match_or_guard_scope(Meta, 'function', S),
5757
elixir_translator:translate_fn(Meta, Pairs, S);
5858

59-
translate({ function, Meta, [{ '/', _, [{{ '.', _ ,[M, F] }, _ , [] }, A]}] }, S) when is_atom(F), is_integer(A) ->
59+
translate({ function, _, [{ '/', _, [{{ '.', Meta, [M, F] }, _ , []}, A]}] }, S) when is_atom(F), is_integer(A) ->
6060
translate({ function, Meta, [M, F, A] }, S);
6161

62-
translate({ function, Meta, [{ '/', _, [{F, _, C}, A]}] }, S) when is_atom(F), is_integer(A), is_atom(C) ->
62+
translate({ function, _, [{ '/', _, [{F, Meta, C}, A]}] }, S) when is_atom(F), is_integer(A), is_atom(C) ->
6363
assert_no_match_or_guard_scope(Meta, 'function', S),
6464

6565
case elixir_dispatch:import_function(Meta, F, A, S) of

lib/elixir/src/elixir_scope.erl

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
build_erl_var/2, build_ex_var/2,
66
serialize/1, deserialize/1,
77
serialize_with_vars/2, deserialize_with_vars/2,
8-
to_erl_env/1, to_ex_env/1, filename/1,
8+
to_erl_env/1, to_ex_env/1,
99
umergev/2, umergec/2, merge_clause_vars/2
10-
]).
10+
]).
1111
-include("elixir.hrl").
1212
-compile({parse_transform, elixir_transform}).
1313

@@ -77,20 +77,16 @@ build_ex_var(Line, Key, Name, S) when is_integer(Line) ->
7777

7878
% Handle Macro.Env conversion
7979

80-
to_erl_env(Scope) ->
81-
elixir_tree_helpers:abstract_syntax(to_ex_env(Scope)).
82-
83-
to_ex_env({ Line, Tuple }) when element(1, Tuple) == 'Elixir.Macro.Env', is_integer(Line) ->
84-
setelement(4, Tuple, Line);
80+
to_erl_env({ 'Elixir.Macro.Env', Module, File, _Line, Function, Aliases, Context, Requires, Functions, Macros }) ->
81+
#elixir_scope{module=Module,file=File,
82+
function=Function,aliases=Aliases,context=Context,
83+
requires=Requires,macros=Macros,functions=Functions}.
8584

8685
to_ex_env({ Line, #elixir_scope{module=Module,file=File,
8786
function=Function,aliases=Aliases,context=Context,
8887
requires=Requires,macros=Macros,functions=Functions} }) when is_integer(Line) ->
8988
{ 'Elixir.Macro.Env', Module, File, Line, Function, Aliases, Context, Requires, Functions, Macros }.
9089

91-
filename(#elixir_scope{file=File}) -> File;
92-
filename(Other) -> element(3, Other).
93-
9490
% Provides a tuple with only the scope information we want to serialize.
9591

9692
serialize(S) ->

lib/elixir/src/elixir_translator.erl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ translate_each({ '__FILE__', _Meta, Atom }, S) when is_atom(Atom) ->
207207
translate_each(S#elixir_scope.file, S);
208208

209209
translate_each({ '__ENV__', Meta, Atom }, S) when is_atom(Atom) ->
210-
{ elixir_scope:to_erl_env({ ?line(Meta), S }), S };
210+
Env = elixir_scope:to_ex_env({ ?line(Meta), S }),
211+
{ elixir_tree_helpers:abstract_syntax(Env), S };
211212

212213
translate_each({ '__CALLER__', Meta, Atom }, S) when is_atom(Atom) ->
213214
{ { var, ?line(Meta), '__CALLER__' }, S#elixir_scope{caller=true} };
@@ -438,8 +439,8 @@ translate_each({ Atom, Meta, Args } = Original, S) when is_atom(Atom) ->
438439
Arity = length(Args),
439440
File = S#elixir_scope.file,
440441
case Arity of
441-
0 -> syntax_error(Meta, File, "unknown variable ~s or cannot invoke local ~s/~B inside guard", [Atom, Atom, Arity]);
442-
_ -> syntax_error(Meta, File, "cannot invoke local ~s/~B inside guard", [Atom, Arity])
442+
0 -> syntax_error(Meta, File, "unknown variable ~ts or cannot invoke local ~ts/~B inside guard", [Atom, Atom, Arity]);
443+
_ -> syntax_error(Meta, File, "cannot invoke local ~ts/~B inside guard", [Atom, Arity])
443444
end;
444445
_ ->
445446
translate_local(Meta, Atom, Args, S)

0 commit comments

Comments
 (0)