Skip to content

Commit 56fdf98

Browse files
committed
Add implementations for Collectable
1 parent dd7de56 commit 56fdf98

File tree

6 files changed

+90
-22
lines changed

6 files changed

+90
-22
lines changed

lib/elixir_script/prelude/collectable.ex

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,33 @@ defprotocol ElixirScript.Collectable do
22
@moduledoc false
33
def into(collectable)
44
end
5+
6+
defimpl Collectable, for: List do
7+
def into(original) do
8+
{[], fn
9+
list, {:cont, x} -> list ++ [x]
10+
list, :done -> original ++ list
11+
_, :halt -> :ok
12+
end}
13+
end
14+
end
15+
16+
defimpl Collectable, for: BitString do
17+
def into(original) do
18+
{original, fn
19+
acc, {:cont, x} when is_bitstring(x) -> <<acc::bitstring, x::bitstring>>
20+
acc, :done -> acc
21+
_, :halt -> :ok
22+
end}
23+
end
24+
end
25+
26+
defimpl Collectable, for: Map do
27+
def into(original) do
28+
{original, fn
29+
map, {:cont, {k, v}} -> Map.put(map, k, v)
30+
map, :done -> map
31+
_, :halt -> :ok
32+
end}
33+
end
34+
end

lib/elixir_script/translator/kernel/special_forms/for.ex

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ defmodule ElixirScript.Translator.For do
55
alias ElixirScript.Translator.PatternMatching
66
alias ElixirScript.Translator.Primitive
77
alias ElixirScript.Translator.Function
8+
alias ElixirScript.Translator.Utils
89

910

1011
def make_for(generators, env) do
12+
ElixirScript.Translator.State.add_module_reference(env.state, env.module, ElixirScript.Collectable)
1113
args = handle_args(generators, env)
1214

1315
generators = JS.array_expression(args.generators)
@@ -36,7 +38,7 @@ defmodule ElixirScript.Translator.For do
3638
Primitive.special_forms(),
3739
JS.identifier("_for")
3840
),
39-
[expression, generators, into]
41+
[expression, generators, JS.identifier(Utils.name_to_js_name(ElixirScript.Collectable)), into]
4042
)
4143

4244
{ js_ast, env }

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"dependencies": {
2222
"erlang-types": "^1.0.0",
2323
"erlang-processes": "^2.0.0",
24-
"tailored": "2.3.1"
24+
"tailored": "2.3.2"
2525
},
2626
"devDependencies": {
2727
"babel": "^6.5.2",

src/javascript/lib/core/special_forms.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,21 @@ function map_update(map, values) {
2020
);
2121
}
2222

23-
function _for(expression, generators, into = []) {
24-
const generatedValues = run_list_generators(generators.pop()(), generators);
23+
function _for(expression, generators, collectable_protocol, into = []) {
24+
let [result, fun] = collectable_protocol.into(into);
2525

26-
let result = into;
26+
const generatedValues = run_list_generators(generators.pop()(), generators);
2727

2828
for (let value of generatedValues) {
2929
if (expression.guard.apply(this, value)) {
30-
result = result.concat([expression.fn.apply(this, value)]);
30+
result = fun(result, new Core.Tuple(
31+
Symbol.for("cont"),
32+
expression.fn.apply(this, value)
33+
));
3134
}
3235
}
3336

34-
return result;
37+
return fun(result, Symbol.for("done"));
3538
}
3639

3740
function run_list_generators(generator, generators) {

src/javascript/tests/for.spec.js

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,33 @@ var expect = chai.expect;
1111

1212
const $ = Patterns.variable();
1313

14+
const collectable = {
15+
into: function(original) {
16+
const fun = Patterns.defmatch(
17+
Patterns.clause(
18+
[
19+
$,
20+
Patterns.type(Tuple, {
21+
values: [Symbol.for("cont"), Patterns.variable()]
22+
})
23+
],
24+
(list, x) => list.concat([x])
25+
),
26+
Patterns.clause([$, Symbol.for("done")], list => list)
27+
);
28+
29+
return new Tuple([], fun);
30+
}
31+
};
32+
1433
describe("for", () => {
1534
it("simple for", () => {
1635
let gen = Patterns.list_generator($, [1, 2, 3, 4]);
17-
let result = SpecialForms._for(Patterns.clause([$], x => x * 2), [gen]);
36+
let result = SpecialForms._for(
37+
Patterns.clause([$], x => x * 2),
38+
[gen],
39+
collectable
40+
);
1841

1942
expect(result).to.eql([2, 4, 6, 8]);
2043
});
@@ -24,10 +47,11 @@ describe("for", () => {
2447

2548
let gen = Patterns.list_generator($, [1, 2]);
2649
let gen2 = Patterns.list_generator($, [2, 3]);
27-
let result = SpecialForms._for(Patterns.clause([$, $], (x, y) => x * y), [
28-
gen,
29-
gen2
30-
]);
50+
let result = SpecialForms._for(
51+
Patterns.clause([$, $], (x, y) => x * y),
52+
[gen, gen2],
53+
collectable
54+
);
3155

3256
expect(result).to.eql([2, 3, 4, 6]);
3357
});
@@ -37,7 +61,8 @@ describe("for", () => {
3761
let gen = Patterns.list_generator($, [1, 2, 3, 4, 5, 6]);
3862
let result = SpecialForms._for(
3963
Patterns.clause([$], x => x, x => x % 2 === 0),
40-
[gen]
64+
[gen],
65+
collectable
4166
);
4267

4368
expect(result).to.eql([2, 4, 6]);
@@ -56,7 +81,8 @@ describe("for", () => {
5681

5782
let result = SpecialForms._for(
5883
Patterns.clause([[Symbol.for("user"), $]], name => name.toUpperCase()),
59-
[gen]
84+
[gen],
85+
collectable
6086
);
6187

6288
expect(result).to.eql(["JOHN", "MEG"]);
@@ -98,7 +124,7 @@ describe("for", () => {
98124
(r, g, b) => new Tuple(r, g, b)
99125
);
100126

101-
let result = SpecialForms._for(expression, [gen]);
127+
let result = SpecialForms._for(expression, [gen], collectable);
102128

103129
expect(result).to.eql([
104130
new Tuple(213, 45, 132),

test/translator/for_test.exs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ defmodule ElixirScript.Translator.For.Test do
2323
Elixir.Core.Patterns.variable(),
2424
Object.freeze([1, 2, 3, 4])
2525
)
26-
],
26+
],
27+
Elixir$ElixirScript$Collectable,
2728
Object.freeze([])
2829
)
2930
"""
@@ -52,7 +53,8 @@ defmodule ElixirScript.Translator.For.Test do
5253
Elixir.Core.Patterns.variable(),
5354
Object.freeze([1, 2, 3, 4])
5455
)
55-
],
56+
],
57+
Elixir$ElixirScript$Collectable,
5658
Object.freeze([])
5759
)
5860
"""
@@ -81,7 +83,8 @@ defmodule ElixirScript.Translator.For.Test do
8183
Elixir.Core.Patterns.variable(),
8284
'Opera'
8385
)
84-
],
86+
],
87+
Elixir$ElixirScript$Collectable,
8588
Object.freeze([])
8689
)
8790
"""
@@ -114,7 +117,8 @@ defmodule ElixirScript.Translator.For.Test do
114117
Elixir.Core.Patterns.variable(),
115118
Object.freeze([2, 3])
116119
)
117-
],
120+
],
121+
Elixir$ElixirScript$Collectable,
118122
Object.freeze([])
119123
)
120124
"""
@@ -152,6 +156,7 @@ defmodule ElixirScript.Translator.For.Test do
152156
Object.freeze([2, 3])
153157
)
154158
],
159+
Elixir$ElixirScript$Collectable,
155160
Object.freeze([])
156161
)
157162
);
@@ -181,7 +186,8 @@ defmodule ElixirScript.Translator.For.Test do
181186
Elixir.Core.Patterns.variable(),
182187
Object.freeze([1, 2, 3, 4, 5, 6])
183188
)
184-
],
189+
],
190+
Elixir$ElixirScript$Collectable,
185191
Object.freeze([])
186192
)
187193
"""
@@ -209,7 +215,8 @@ defmodule ElixirScript.Translator.For.Test do
209215
Elixir.Core.Patterns.list_generator(Elixir.Core.Patterns.type(Elixir.Core.Tuple, {
210216
values: [Symbol.for('user'), Elixir.Core.Patterns.variable()]
211217
}), Object.freeze([new Elixir.Core.Tuple(Symbol.for('user'), 'john'), new Elixir.Core.Tuple(Symbol.for('admin'), 'john'), new Elixir.Core.Tuple(Symbol.for('user'), 'meg')]))
212-
],
218+
],
219+
Elixir$ElixirScript$Collectable,
213220
Object.freeze([]))
214221
"""
215222

@@ -240,7 +247,7 @@ defmodule ElixirScript.Translator.For.Test do
240247
'value': Elixir.Core.Patterns.variable()
241248
}, 8), Elixir.Core.BitString.size({
242249
'value': Elixir.Core.Patterns.variable()
243-
}, 8)), pixels)], Object.freeze([]))
250+
}, 8)), pixels)], Elixir$ElixirScript$Collectable, Object.freeze([]))
244251
"""
245252

246253
assert_translation(ex_ast, js_code)

0 commit comments

Comments
 (0)