@@ -208,7 +208,7 @@ defmodule Exception do
|
||||
{_, kind, _, clauses} <- List.keyfind(defs, {function, arity}, 0) do
|
||||
clauses =
|
||||
for {meta, ex_args, guards, _block} <- clauses do
|
||||
scope = :elixir_erl.scope(meta)
|
||||
scope = :elixir_erl.scope(meta, true)
|
||||
|
||||
{erl_args, scope} =
|
||||
:elixir_erl_clauses.match(&:elixir_erl_pass.translate_args/2, ex_args, scope)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
backup_vars=nil, %% a copy of vars to be used on ^var
|
||||
extra_guards=[], %% extra guards from args expansion
|
||||
counter=#{}, %% a map counting the variables defined
|
||||
expand_captures=false, %% a boolean to control if captures should be expanded
|
||||
stacktrace=false %% holds information about the stacktrace variable
|
||||
}).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%% Compiler backend to Erlang.
|
||||
-module(elixir_erl).
|
||||
-export([elixir_to_erl/1, definition_to_anonymous/4, compile/1, consolidate/3,
|
||||
get_ann/1, debug_info/4, scope/1, format_error/1]).
|
||||
get_ann/1, debug_info/4, scope/2, format_error/1]).
|
||||
-include("elixir.hrl").
|
||||
-define(typespecs, 'Elixir.Kernel.Typespec').
|
||||
|
||||
@@ -48,7 +48,7 @@ get_ann([], Gen, Line) -> erl_anno:set_generated(Gen, Line).
|
||||
%% Converts an Elixir definition to an anonymous function.
|
||||
|
||||
definition_to_anonymous(Module, Kind, Meta, Clauses) ->
|
||||
ErlClauses = [translate_clause(Kind, Clause) || Clause <- Clauses],
|
||||
ErlClauses = [translate_clause(Kind, Clause, true) || Clause <- Clauses],
|
||||
Fun = {'fun', ?ann(Meta), {clauses, ErlClauses}},
|
||||
LocalHandler = fun(LocalName, LocalArgs) -> invoke_local(Module, LocalName, LocalArgs) end,
|
||||
{value, Result, _Binding} = erl_eval:expr(Fun, [], {value, LocalHandler}),
|
||||
@@ -117,8 +117,8 @@ elixir_to_erl_cons(T) -> elixir_to_erl(T).
|
||||
|
||||
%% Returns a scope for translation.
|
||||
|
||||
scope(_Meta) ->
|
||||
#elixir_erl{}.
|
||||
scope(_Meta, ExpandCaptures) ->
|
||||
#elixir_erl{expand_captures=ExpandCaptures}.
|
||||
|
||||
%% Static compilation hook, used in protocol consolidation
|
||||
|
||||
@@ -220,15 +220,15 @@ add_definition(Meta, Body, {Head, Tail}) ->
|
||||
end.
|
||||
|
||||
translate_definition(Kind, Meta, {Name, Arity}, Clauses) ->
|
||||
ErlClauses = [translate_clause(Kind, Clause) || Clause <- Clauses],
|
||||
ErlClauses = [translate_clause(Kind, Clause, false) || Clause <- Clauses],
|
||||
|
||||
case is_macro(Kind) of
|
||||
true -> {function, ?ann(Meta), elixir_utils:macro_name(Name), Arity + 1, ErlClauses};
|
||||
false -> {function, ?ann(Meta), Name, Arity, ErlClauses}
|
||||
end.
|
||||
|
||||
translate_clause(Kind, {Meta, Args, Guards, Body}) ->
|
||||
S = scope(Meta),
|
||||
translate_clause(Kind, {Meta, Args, Guards, Body}, ExpandCaptures) ->
|
||||
S = scope(Meta, ExpandCaptures),
|
||||
|
||||
{TClause, TS} = elixir_erl_clauses:clause(Meta,
|
||||
fun elixir_erl_pass:translate_args/2, Args, Body, Guards, S),
|
||||
|
||||
@@ -96,7 +96,15 @@ translate({'&', Meta, [{'/', _, [{{'.', _, [Remote, Fun]}, _, []}, Arity]}]}, S)
|
||||
{{'fun', Ann, {function, TRemote, TFun, TArity}}, SR};
|
||||
translate({'&', Meta, [{'/', _, [{Fun, _, Atom}, Arity]}]}, S)
|
||||
when is_atom(Fun), is_atom(Atom), is_integer(Arity) ->
|
||||
{{'fun', ?ann(Meta), {function, Fun, Arity}}, S};
|
||||
case S of
|
||||
#elixir_erl{expand_captures=true} ->
|
||||
Vars = [{list_to_atom("arg" ++ integer_to_list(Counter)), [], ?MODULE}
|
||||
|| Counter <- tl(lists:seq(0, Arity))],
|
||||
translate({'fn', Meta, [{'->', Meta, [Vars, {Fun, Meta, Vars}]}]}, S);
|
||||
|
||||
#elixir_erl{expand_captures=false} ->
|
||||
{{'fun', ?ann(Meta), {function, Fun, Arity}}, S}
|
||||
end;
|
||||
|
||||
translate({fn, Meta, Clauses}, S) ->
|
||||
Transformer = fun({'->', CMeta, [ArgsWithGuards, Expr]}, Acc) ->
|
||||
|
||||
@@ -34,6 +34,10 @@ defmodule Kernel.MacrosTest do
|
||||
quote(do: 1 + unquote(value))
|
||||
end
|
||||
|
||||
defmacro my_macro_with_capture(value) do
|
||||
Enum.map(value, &by_two/1)
|
||||
end
|
||||
|
||||
test "require" do
|
||||
assert Kernel.MacrosTest.Nested.value() == 1
|
||||
end
|
||||
@@ -42,7 +46,7 @@ defmodule Kernel.MacrosTest do
|
||||
assert Nested.value() == 1
|
||||
end
|
||||
|
||||
test "local but private macro" do
|
||||
test "local with private macro" do
|
||||
assert my_private_macro() == 4
|
||||
end
|
||||
|
||||
@@ -54,6 +58,10 @@ defmodule Kernel.MacrosTest do
|
||||
assert my_macro_with_local(4) == 17
|
||||
end
|
||||
|
||||
test "local with capture" do
|
||||
assert my_macro_with_capture([1, 2, 3]) == [2, 4, 6]
|
||||
end
|
||||
|
||||
test "macros cannot be called dynamically" do
|
||||
x = Nested
|
||||
assert_raise UndefinedFunctionError, fn -> x.value end
|
||||
|
||||
Reference in New Issue
Block a user