forked from elixir-lang/elixir
-
Notifications
You must be signed in to change notification settings - Fork 0
/
elixir_def_defaults.erl
59 lines (42 loc) · 2.02 KB
/
elixir_def_defaults.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
% Handle default clauses for function definitions.
-module(elixir_def_defaults).
-export([unpack/4]).
-include("elixir.hrl").
% Unpack default args from the given clause. Invoked by elixir_translate.
unpack(Kind, Name, Args, S) ->
unpack_each(Kind, Name, Args, [], [], S).
%% Helpers
%% Unpack default from given args.
%% Returns the given arguments without their default
%% clauses and a list of clauses for the default calls.
unpack_each(Kind, Name, [{'//', Line, [Expr, _]}|T] = List, Acc, Clauses, S) ->
Base = build_match(Acc, Line, []),
{ Args, Invoke } = extract_defaults(List, [], []),
SM = S#elixir_scope{counter=length(Base)},
{ DefArgs, SA } = elixir_clauses:assigns(fun elixir_translator:translate/2, Base ++ Args, SM),
{ InvokeArgs, _ } = elixir_translator:translate_args(Base ++ Invoke, SA),
Call = { call, Line,
{ atom, Line, name_for_kind(Kind, Name) },
InvokeArgs
},
Clause = { clause, Line, DefArgs, [], [Call] },
unpack_each(Kind, Name, T, [Expr|Acc], [Clause|Clauses], S);
unpack_each(Kind, Name, [H|T], Acc, Clauses, S) ->
unpack_each(Kind, Name, T, [H|Acc], Clauses, S);
unpack_each(_Kind, _Name, [], Acc, Clauses, _S) ->
{ lists:reverse(Acc), lists:reverse(Clauses) }.
% Extract default values from args following the current default clause.
extract_defaults([{'//', _, [_Expr, Default]}|T], NewArgs, NewInvoke) ->
extract_defaults(T, NewArgs, [Default|NewInvoke]);
extract_defaults([H|T], NewArgs, NewInvoke) ->
extract_defaults(T, [H|NewArgs], [H|NewInvoke]);
extract_defaults([], NewArgs, NewInvoke) ->
{ lists:reverse(NewArgs), lists:reverse(NewInvoke) }.
% Build matches for all the previous argument until the current default clause.
build_match([], _Line, Acc) -> Acc;
build_match([_|T], Line, Acc) ->
Var = { ?ELIXIR_ATOM_CONCAT(["_EX", length(T)]), Line, nil },
build_match(T, Line, [Var|Acc]).
% Given the invoked function name based on the kind
name_for_kind(Kind, Name) when Kind == defmacro; Kind == defmacrop -> ?ELIXIR_MACRO(Name);
name_for_kind(_Kind, Name) -> Name.