Skip to content

Commit 93f71c8

Browse files
author
José Valim
committed
Expand macros and quoted variables inside << >>, closes #1063
1 parent 8154066 commit 93f71c8

File tree

2 files changed

+66
-44
lines changed

2 files changed

+66
-44
lines changed

lib/elixir/src/elixir_literal.erl

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ translate({ '<<>>', Meta, Args } = Original, S) when is_list(Args) ->
1010
error ->
1111
case S#elixir_scope.context of
1212
match ->
13-
build_bitstr(fun elixir_translator:translate_each/2, Args, Meta, S);
13+
build_bitstr(fun elixir_translator:translate_each/2, Args, Meta, nil, S);
1414
_ ->
15-
{ TArgs, { SC, SV } } = build_bitstr(fun elixir_translator:translate_arg/2, Args, Meta, { S, S }),
15+
{ TArgs, { SC, SV } } = build_bitstr(fun elixir_translator:translate_arg/2, Args, Meta, nil, { S, S }),
1616
{ TArgs, umergec(SV, SC) }
1717
end;
1818
Else -> Else
@@ -75,58 +75,72 @@ translate(Bitstring, S) when is_bitstring(Bitstring) ->
7575
% * If '::' is given, extract the bitstring information
7676
% * All the other types are simply translated and handled with Erlang's default
7777
%
78-
build_bitstr(Fun, Exprs, Meta, S) ->
79-
{ Final, FinalS } = build_bitstr_each(Fun, Exprs, Meta, S, []),
78+
build_bitstr(Fun, Exprs, Meta, Env, S) ->
79+
{ Final, FinalS } = build_bitstr_each(Fun, Exprs, Meta, Env, S, []),
8080
{ { bin, ?line(Meta), lists:reverse(Final) }, FinalS }.
8181

82-
build_bitstr_each(_Fun, [], _Meta, S, Acc) ->
82+
build_bitstr_each(_Fun, [], _Meta, _Env, S, Acc) ->
8383
{ Acc, S };
8484

85-
build_bitstr_each(Fun, [{'::',_,[H,V]}|T], Meta, S, Acc) ->
85+
build_bitstr_each(Fun, [{'::',_,[H,V]}|T], Meta, Env, S, Acc) ->
8686
%% Variables defined outside the binary can be accounted
8787
%% on subparts, however we can't assign new variables.
8888
case S of
8989
{ ES, _ } -> []; %% translate_arg, no assigns
9090
_ -> ES = S#elixir_scope{context=nil} %% translate_each, revert assigns
9191
end,
9292

93-
{ Size, Types } = extract_bit_values(Meta, V, ES),
94-
build_bitstr_each(Fun, T, Meta, S, Acc, H, Size, Types);
93+
{ ExpandedH, ExpandedEnv } = expand(Meta, H, Env, S),
94+
{ Size, Types } = extract_bit_values(Meta, V, ExpandedEnv, ES),
95+
build_bitstr_each(Fun, T, Meta, ExpandedEnv, S, Acc, ExpandedH, Size, Types);
9596

96-
build_bitstr_each(Fun, [H|T], Meta, S, Acc) ->
97-
build_bitstr_each(Fun, T, Meta, S, Acc, H, default, default).
97+
build_bitstr_each(Fun, [H|T], Meta, Env, S, Acc) ->
98+
{ ExpandedH, ExpandedEnv } = expand(Meta, H, Env, S),
99+
build_bitstr_each(Fun, T, Meta, ExpandedEnv, S, Acc, ExpandedH, default, default).
98100

99-
build_bitstr_each(Fun, T, Meta, S, Acc, H, Size, Types) when is_list(H) ->
101+
expand(_Meta, H, Env, _S) when is_integer(H); is_float(H); is_atom(H); is_atom(H); is_bitstring(H) ->
102+
{ H, Env };
103+
104+
expand(Meta, H, nil, { S, _ }) ->
105+
expand(Meta, H, elixir_scope:to_ex_env({ ?line(Meta), S }), S);
106+
107+
expand(Meta, H, nil, S) ->
108+
expand(Meta, H, elixir_scope:to_ex_env({ ?line(Meta), S }), S);
109+
110+
expand(_Meta, H, Env, _S) ->
111+
{ 'Elixir.Macro':expand(H, Env), Env }.
112+
113+
build_bitstr_each(Fun, T, Meta, Env, S, Acc, H, Size, Types) when is_list(H) ->
100114
case is_default_or_utf(Types) of
101115
true ->
102116
{ NewAcc, NewS } = lists:foldl(fun(L, { LA, LS }) ->
103117
{ FL, FS } = Fun(L, LS),
104118
{ [{ bin_element, ?line(Meta), FL, Size, Types }|LA], FS }
105119
end, { Acc, S }, H),
106-
build_bitstr_each(Fun, T, Meta, NewS, NewAcc);
120+
build_bitstr_each(Fun, T, Meta, Env, NewS, NewAcc);
107121
false ->
108-
build_bitstr_default(Fun, T, Meta, S, Acc, H, Size, Types)
122+
build_bitstr_default(Fun, T, Meta, Env, S, Acc, H, Size, Types)
109123
end;
110124

111-
build_bitstr_each(Fun, T, Meta, S, Acc, H, Size, Types) when is_bitstring(H) ->
125+
build_bitstr_each(Fun, T, Meta, Env, S, Acc, H, Size, Types) when is_bitstring(H) ->
112126
case is_default_or_utf(Types) of
113127
true ->
114128
Line = ?line(Meta),
115129
{ bin, _, Elements } = elixir_tree_helpers:elixir_to_erl(H),
116130
NewAcc = lists:foldl(fun({ bin_element, _, Expr, _, _ }, FinalAcc) ->
117131
[{ bin_element, Line, Expr, Size, Types }|FinalAcc]
118132
end, Acc, Elements),
119-
build_bitstr_each(Fun, T, Meta, S, NewAcc);
133+
build_bitstr_each(Fun, T, Meta, Env, S, NewAcc);
120134
false ->
121-
build_bitstr_default(Fun, T, Meta, S, Acc, H, Size, Types)
135+
build_bitstr_default(Fun, T, Meta, Env, S, Acc, H, Size, Types)
122136
end;
123137

124-
build_bitstr_each(Fun, T, Meta, S, Acc, H, Size, Types) ->
125-
build_bitstr_default(Fun, T, Meta, S, Acc, H, Size, Types).
138+
build_bitstr_each(Fun, T, Meta, Env, S, Acc, H, Size, Types) ->
139+
build_bitstr_default(Fun, T, Meta, Env, S, Acc, H, Size, Types).
126140

127-
build_bitstr_default(Fun, T, Meta, S, Acc, H, Size, Types) ->
141+
build_bitstr_default(Fun, T, Meta, Env, S, Acc, H, Size, Types) ->
128142
{ Expr, NS } = Fun(H, S),
129-
build_bitstr_each(Fun, T, Meta, NS, [{ bin_element, ?line(Meta), Expr, Size, Types }|Acc]).
143+
build_bitstr_each(Fun, T, Meta, Env, NS, [{ bin_element, ?line(Meta), Expr, Size, Types }|Acc]).
130144

131145
is_default_or_utf(default) -> true;
132146
is_default_or_utf([UTF|_]) when UTF == utf8; UTF == utf16; UTF == utf32 -> true;
@@ -135,46 +149,46 @@ is_default_or_utf([]) -> false.
135149

136150
%% Extra bitstring specifiers
137151

138-
extract_bit_values(Meta, V, S) when is_list(V) ->
139-
extract_bit_values(Meta, V, default, [], S);
152+
extract_bit_values(Meta, V, Env, S) when is_list(V) ->
153+
extract_bit_values(Meta, V, default, [], Env, S);
140154

141-
extract_bit_values(Meta, V, S) ->
142-
extract_bit_values(Meta, [V], S).
155+
extract_bit_values(Meta, V, Env, S) ->
156+
extract_bit_values(Meta, [V], Env, S).
143157

144-
extract_bit_values(Meta, [{ Value, _Meta, Atom }|T] = All, Size, Types, S)
158+
extract_bit_values(Meta, [{ Value, _Meta, Atom }|T] = All, Size, Types, Env, S)
145159
when is_atom(Value) andalso (is_atom(Atom) orelse Atom == []) ->
146160
case extract_bit_type(Value, Types) of
147161
{ error, unknown } ->
148-
handle_unknown_specifier(Meta, All, Size, Types, S);
162+
handle_unknown_specifier(Meta, All, Size, Types, Env, S);
149163
NewTypes when is_list(NewTypes) ->
150-
extract_bit_values(Meta, T, Size, NewTypes, S)
164+
extract_bit_values(Meta, T, Size, NewTypes, Env, S)
151165
end;
152166

153-
extract_bit_values(Meta, [{ Value, CallMeta, [_] = Args }|T] = All, Size, Types, S) when is_atom(Value) ->
167+
extract_bit_values(Meta, [{ Value, CallMeta, [_] = Args }|T] = All, Size, Types, Env, S) when is_atom(Value) ->
154168
{ TArgs, _ } = elixir_translator:translate_args(Args, S),
155169
case extract_bit_type_or_size(Value, TArgs, Size, Types) of
156170
{ error, unknown } ->
157-
handle_unknown_specifier(Meta, All, Size, Types, S);
171+
handle_unknown_specifier(Meta, All, Size, Types, Env, S);
158172
{ error, Msg } ->
159173
elixir_errors:syntax_error(CallMeta, S#elixir_scope.file, Msg);
160174
{ NewSize, NewTypes } ->
161-
extract_bit_values(Meta, T, NewSize, NewTypes, S)
175+
extract_bit_values(Meta, T, NewSize, NewTypes, Env, S)
162176
end;
163177

164-
extract_bit_values(Meta, [Size|T], default, Types, S) when is_integer(Size) andalso Size >= 0 ->
165-
extract_bit_values(Meta, T, {integer, Meta, Size}, Types, S);
178+
extract_bit_values(Meta, [Size|T], default, Types, Env, S) when is_integer(Size) andalso Size >= 0 ->
179+
extract_bit_values(Meta, T, {integer, Meta, Size}, Types, Env, S);
166180

167-
extract_bit_values(Meta, [{ '|', _, [Left, Right] }], Size, Types, S) ->
168-
Expanded = 'Elixir.Macro':expand(Right, elixir_scope:to_ex_env({ ?line(Meta), S })),
169-
extract_bit_values(Meta, [Left|join_expansion(Expanded,[])], Size, Types, S);
181+
extract_bit_values(Meta, [{ '|', _, [Left, Right] }], Size, Types, Env, S) ->
182+
{ Expanded, ExpandedEnv } = expand(Meta, Right, Env, S),
183+
extract_bit_values(Meta, [Left|join_expansion(Expanded,[])], Size, Types, ExpandedEnv, S);
170184

171-
extract_bit_values(Meta, [_|_] = All, Size, Types, S) ->
172-
handle_unknown_specifier(Meta, All, Size, Types, S);
185+
extract_bit_values(Meta, [_|_] = All, Size, Types, Env, S) ->
186+
handle_unknown_specifier(Meta, All, Size, Types, Env, S);
173187

174-
extract_bit_values(_Meta, [], Size, [], _S) ->
188+
extract_bit_values(_Meta, [], Size, [], _Env, _S) ->
175189
{ Size, default };
176190

177-
extract_bit_values(_Meta, [], Size, Types, _S) ->
191+
extract_bit_values(_Meta, [], Size, Types, _Env, _S) ->
178192
{ Size, lists:reverse(Types) }.
179193

180194
extract_bit_type(Value, Types) when
@@ -206,12 +220,12 @@ extract_bit_type_or_size(unit, _Args, _Other, _Types) ->
206220
extract_bit_type_or_size(_Value, _Args, _Other, _Types) ->
207221
{ error, unknown }.
208222

209-
handle_unknown_specifier(Meta, [H|T], Size, Types, S) ->
210-
case 'Elixir.Macro':expand(H, elixir_scope:to_ex_env({ ?line(Meta), S })) of
211-
H ->
223+
handle_unknown_specifier(Meta, [H|T], Size, Types, Env, S) ->
224+
case expand(Meta, H, Env, S) of
225+
{ H, _ } ->
212226
elixir_errors:syntax_error(Meta, S#elixir_scope.file, "unknown bitstring specifier ~ts", ['Elixir.Macro':to_binary(H)]);
213-
E ->
214-
extract_bit_values(Meta, join_expansion(E,T), Size, Types, S)
227+
{ E, ExpandedEnv } ->
228+
extract_bit_values(Meta, join_expansion(E,T), Size, Types, ExpandedEnv, S)
215229
end.
216230

217231
join_expansion({ '__block__', _, [Expanded] }, Tail) -> join_expansion(Expanded, Tail);

lib/elixir/test/elixir/binary_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,14 @@ bar
9898
assert <<0,0,0,106,0,0,0,111,0,0,0,115,0,0,0,101>> == << 'jose' :: utf32 >>
9999
end
100100

101+
@binary "new "
102+
@charlist 'old '
103+
104+
test :bitsyntax_with_expansion do
105+
assert <<@binary, "world">> == "new world"
106+
assert <<@charlist, "world">> == "old world"
107+
end
108+
101109
test :bitsyntax_translation do
102110
refb = "sample"
103111
sec_data = "another"

0 commit comments

Comments
 (0)