Skip to content

Commit

Permalink
Allow macros to be invoked __MODULE__.macro during compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
José Valim committed Apr 22, 2012
1 parent 6fdbb5d commit e612fb7
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 13 deletions.
13 changes: 7 additions & 6 deletions src/elixir_def_local.erl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
build_table/1,
delete_table/1,
record/4,
macro_for/2,
macro_for/3,
function_for/3,
format_error/1,
check_unused_local_macros/3,
Expand All @@ -22,18 +22,18 @@ build_table(Module) ->
delete_table(Module) ->
ets:delete(table(Module)).

record(_Line, _Tuple, _IsMacro, #elixir_scope{module=[]}) -> [];
record(_Line, _Tuple, _IsMacro, []) -> [];

record(Line, Tuple, IsMacro, #elixir_scope{module=Module}) ->
record(Line, Tuple, IsMacro, Module) ->
ets:insert(table(Module), { Tuple, Line, IsMacro }).

%% Reading

macro_for(_Tuple, #elixir_scope{module=[]}) -> false;
macro_for(_Tuple, _All, #elixir_scope{module=[]}) -> false;

macro_for(Tuple, #elixir_scope{module=Module}) ->
macro_for(Tuple, All, #elixir_scope{module=Module}) ->
case ets:lookup(elixir_def:table(Module), Tuple) of
[{Tuple, Line, Kind, _, Clauses}] when Kind == defmacro; Kind == defmacrop ->
[{Tuple, Line, Kind, _, Clauses}] when Kind == defmacro; All, Kind == defmacrop ->
RewrittenClauses = [rewrite_clause(Clause, Module) || Clause <- Clauses],
Fun = { 'fun', Line, {clauses, lists:reverse(RewrittenClauses)} },
{ value, Result, _Binding } = erl_eval:exprs([Fun], []),
Expand All @@ -45,6 +45,7 @@ function_for(Module, Name, Arity) ->
Tuple = { Name, Arity },
case ets:lookup(elixir_def:table(Module), Tuple) of
[{Tuple, Line, _, _, Clauses}] ->
% elixir_def_local:record(Line, Tuple, false, Module),
RewrittenClauses = [rewrite_clause(Clause, Module) || Clause <- Clauses],
Fun = { 'fun', Line, {clauses, lists:reverse(RewrittenClauses)} },
{ value, Result, _Binding } = erl_eval:exprs([Fun], []),
Expand Down
19 changes: 14 additions & 5 deletions src/elixir_dispatch.erl
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ dispatch_imports(Line, Name, Args, S, Callback) ->
false ->
case find_dispatch(Tuple, S#elixir_scope.macros) of
false ->
Fun = (S#elixir_scope.function /= Tuple) andalso elixir_def_local:macro_for(Tuple, S),
Fun = (S#elixir_scope.function /= Tuple) andalso elixir_def_local:macro_for(Tuple, true, S),
case Fun of
false -> Callback();
_ ->
Receiver = S#elixir_scope.module,
elixir_def_local:record(Line, Tuple, true, S),
elixir_def_local:record(Line, Tuple, true, Receiver),
dispatch_macro_fun(Line, Fun, Receiver, Name, Arity, Args, S)
end;
Receiver ->
Expand All @@ -91,9 +91,18 @@ dispatch_require(Line, Receiver, Name, Args, S, Callback) ->
Arity = length(Args),
Tuple = {Name, Arity},

case lists:member(Tuple, get_optional_macros(Receiver)) of
true -> dispatch_macro(Line, Receiver, Tuple, Args, S);
false -> Callback()
Fun = (S#elixir_scope.module == Receiver) andalso (S#elixir_scope.function /= Tuple) andalso
elixir_def_local:macro_for(Tuple, false, S),

case Fun of
false ->
case lists:member(Tuple, get_optional_macros(Receiver)) of
true -> dispatch_macro(Line, Receiver, Tuple, Args, S);
false -> Callback()
end;
_ ->
elixir_def_local:record(Line, Tuple, true, Receiver),
dispatch_macro_fun(Line, Fun, Receiver, Name, Arity, Args, S)
end.

%% HELPERS
Expand Down
2 changes: 1 addition & 1 deletion src/elixir_translator.erl
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ translate_each({Atom, Line, Args} = Original, S) when is_atom(Atom) ->
case handle_partials(Line, Original, S) of
error ->
Callback = fun() ->
elixir_def_local:record(Line, { Atom, length(Args) }, false, S),
elixir_def_local:record(Line, { Atom, length(Args) }, false, S#elixir_scope.module),
translate_atom_call(Line, Atom, Args, S)
end,
elixir_dispatch:dispatch_imports(Line, Atom, Args, S, Callback);
Expand Down
5 changes: 5 additions & 0 deletions test/elixir/elixir/errors_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ defmodule Elixir.ErrorsTest do
format_rescue 'defmodule Foo do\ndef foo, do: undefined\ndefmacro undefined, do: 13\nend'
end

test :private_macro do
assert_equal "undefined function: Foo.foo/0",
format_rescue 'defmodule Foo do\ndefmacrop foo, do: 1\ndefmacro bar, do: __MODULE__.foo\ndefmacro baz, do: bar\nend'
end

test :erlang_function_conflict do
assert_equal "nofile:1: function exit/1 already imported from erlang",
format_rescue 'defmodule Foo do import Elixir.ErrorsTest.UnproperMacro, only: [exit: 1]\nend'
Expand Down
2 changes: 1 addition & 1 deletion test/elixir/kernel/require_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ defmodule Kernel.RequireTest do
end

test :locals_are_always_required do
assert_equal 2, my_macro
assert_equal 2, __MODULE__.my_macro
end

test :locals_and_private_are_always_required do
Expand Down

0 comments on commit e612fb7

Please sign in to comment.