Skip to content

Commit af24949

Browse files
authored
Merge pull request #419 from elixirscript/fix-multi-bind
Fix multi bind
2 parents 9aa5349 + e457995 commit af24949

File tree

5 files changed

+117
-25
lines changed

5 files changed

+117
-25
lines changed

lib/elixir_script/passes/translate/forms/match.ex

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,53 @@ defmodule ElixirScript.Translate.Forms.Match do
77
alias ElixirScript.Translate.Forms.Pattern
88

99
def compile({:=, _, [left, right]}, state) do
10+
build_matches(left, right, %{patterns: []})
11+
|> compile_match(state)
12+
end
13+
14+
defp make_list_ref(array_pattern, params) do
15+
{ref, params} = make_params(params)
16+
ref_declaration = Helpers.declare(ref, J.array_expression(params))
17+
18+
[array_pattern, ref_declaration]
19+
end
20+
21+
defp make_tuple_ref(array_pattern, params) do
22+
{ref, params} = make_params(params)
23+
24+
ref_declaration = Helpers.declare(ref, Helpers.new(
25+
Helpers.tuple(),
26+
params
27+
))
28+
[array_pattern, ref_declaration]
29+
end
30+
31+
32+
defp make_params(params) do
33+
ref = J.identifier("_ref#{:rand.uniform(10000000)}")
34+
35+
params = Enum.map(params, fn
36+
(nil) -> J.identifier(:undefined)
37+
(x) -> x
38+
end)
39+
40+
{ ref, params }
41+
end
42+
43+
defp build_matches(pattern, {:=, _, [left, right]}, parts) do
44+
parts = parts
45+
|> Map.update!(:patterns, fn(x) -> x ++ [pattern] end)
46+
47+
build_matches(left, right, parts)
48+
end
49+
50+
defp build_matches(left, right, parts) do
51+
parts
52+
|> Map.update!(:patterns, fn(x) -> x ++ [left] end)
53+
|> Map.put(:expression, right)
54+
end
55+
56+
defp compile_match(%{patterns: [left], expression: right}, state) do
1057
{ right_ast, state } = Form.compile(right, state)
1158

1259
{var_dec, right_ast} = case right_ast do
@@ -47,34 +94,56 @@ defmodule ElixirScript.Translate.Forms.Match do
4794
{ js_ast, state }
4895
end
4996

97+
defp compile_match(%{patterns: lefts, expression: right}, state) do
98+
{ right_ast, state } = Form.compile(right, state)
5099

51-
defp make_list_ref(array_pattern, params) do
52-
{ref, params} = make_params(params)
53-
ref_declaration = Helpers.declare(ref, J.array_expression(params))
54-
55-
[array_pattern, ref_declaration]
56-
end
57-
58-
defp make_tuple_ref(array_pattern, params) do
59-
{ref, params} = make_params(params)
60-
61-
ref_declaration = Helpers.declare(ref, Helpers.new(
62-
Helpers.tuple(),
63-
params
64-
))
65-
[array_pattern, ref_declaration]
66-
end
67-
68-
69-
defp make_params(params) do
70-
ref = J.identifier("_ref#{:rand.uniform(10000000)}")
100+
{var_dec, right_ast} = case right_ast do
101+
[variable_declaration, x] ->
102+
{variable_declaration, x}
103+
x ->
104+
{nil, x}
105+
end
71106

72-
params = Enum.map(params, fn
73-
(nil) -> J.identifier(:undefined)
74-
(x) -> x
107+
intermediate_assign = Helpers.assign(
108+
J.identifier("__intermediate__"),
109+
right_ast
110+
)
111+
112+
{js_ast, state} = Enum.map_reduce(lefts, state, fn(left, state) ->
113+
{ patterns, params, state } = Pattern.compile([left], state)
114+
115+
array_pattern = Helpers.declare(params, Helpers.call(
116+
J.member_expression(
117+
Helpers.patterns(),
118+
J.identifier("match")
119+
),
120+
[hd(patterns), J.identifier("__intermediate__")]
121+
))
122+
123+
js_ast = case left do
124+
list when is_list(list) ->
125+
make_list_ref(array_pattern, params)
126+
{ _, _ } ->
127+
make_tuple_ref(array_pattern, params)
128+
{:{}, _, _ } ->
129+
make_tuple_ref(array_pattern, params)
130+
_ ->
131+
List.wrap(array_pattern)
132+
end
133+
134+
js_ast = case var_dec do
135+
nil ->
136+
js_ast
137+
x ->
138+
[x] ++ js_ast
139+
end
140+
141+
{ js_ast, state }
75142
end)
76143

77-
{ ref, params }
144+
js_ast = [intermediate_assign] ++ List.flatten(js_ast)
145+
146+
{js_ast, state}
78147
end
79148

80149
end

lib/elixir_script/passes/translate/function.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,14 @@ defmodule ElixirScript.Translate.Function do
5858
clauses = compile_clauses(clauses, state)
5959

6060
arg_matches_declaration = Helpers.declare_let("__arg_matches__", J.identifier("null"))
61+
intermediate_declaration = Helpers.declare_let("__intermediate__", J.identifier("null"))
6162

6263
function_recur_dec = Helpers.function(
6364
"recur",
6465
[J.rest_element(J.identifier("__function_args__"))],
6566
J.block_statement([
6667
arg_matches_declaration,
68+
intermediate_declaration,
6769
clauses,
6870
J.throw_statement(
6971
Helpers.new(

test/integration/integration_test.exs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ defmodule ElixirScript.Integration.Test do
3939
val = call_compiled_function Integration, :tuple_get, []
4040
assert val == 5
4141
end
42+
43+
test "multi_bind" do
44+
val = call_compiled_function Integration, :multi_bind, []
45+
assert val == [1, 2, 3, 4, 5]
46+
end
4247
end

test/passes/translate/form_test.exs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ defmodule ElixirScript.Translate.Forms.Test do
1212
{:ok, pid} = ElixirScript.State.start_link()
1313

1414
state = %{
15-
pid: pid
15+
pid: pid,
16+
vars: %{}
1617
}
1718

1819
[state: state]
@@ -178,4 +179,15 @@ defmodule ElixirScript.Translate.Forms.Test do
178179
{js_ast, _} = Form.compile(ast, state)
179180
assert hd(js_ast.arguments).name === "has__qmark__0"
180181
end
182+
183+
test "multi bind", %{state: state} do
184+
ast =
185+
{:=, [line: 35],
186+
[[{:|, [line: 35], [{:a, [line: 35], nil}, {:_, [line: 35], nil}]}],
187+
{:=, [line: 35], [{:b, [line: 35], nil}, [1, 2, 3, 4, 5]]}]}
188+
189+
{js_ast, _} = Form.compile(ast, state)
190+
191+
assert length(js_ast) > 1
192+
end
181193
end

test/support/integration.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ defmodule Integration do
3131
end
3232
end
3333

34+
def multi_bind do
35+
[a | _] = b = [1, 2, 3, 4, 5]
36+
end
37+
3438
def tuple_get do
3539
map = %{{1} => 5}
3640
Map.get(map, {1})

0 commit comments

Comments
 (0)