Skip to content

Commit dd7de56

Browse files
committed
Update implemenation of for
1 parent b42d8ae commit dd7de56

File tree

6 files changed

+357
-225
lines changed

6 files changed

+357
-225
lines changed

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

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,40 @@ defmodule ElixirScript.Translator.For do
1010
def make_for(generators, env) do
1111
args = handle_args(generators, env)
1212

13+
generators = JS.array_expression(args.generators)
14+
1315
collections = Primitive.make_list_no_translate(args.collections)
1416
into = args.into || Primitive.make_list_no_translate([])
1517
filter = args.filter || JS.function_expression([], [], JS.block_statement([JS.return_statement(JS.identifier("true"))]))
1618
fun = args.fun
1719

20+
expression = JS.call_expression(
21+
JS.member_expression(
22+
JS.member_expression(
23+
JS.member_expression(
24+
JS.identifier("Elixir"),
25+
JS.identifier("Core")
26+
),
27+
JS.identifier("Patterns")
28+
),
29+
JS.identifier("clause")
30+
),
31+
[JS.array_expression(args.patterns), fun, filter]
32+
)
33+
1834
js_ast = JS.call_expression(
1935
JS.member_expression(
2036
Primitive.special_forms(),
2137
JS.identifier("_for")
2238
),
23-
[collections, fun, filter, into]
39+
[expression, generators, into]
2440
)
2541

2642
{ js_ast, env }
2743
end
2844

2945
defp handle_args(generators, env) do
30-
Enum.reduce(generators, %{collections: [], args: [], filter: nil, fun: nil, into: nil}, fn
46+
Enum.reduce(generators, %{generators: [], collections: [], args: [], filter: nil, fun: nil, into: nil, patterns: []}, fn
3147

3248
({:<<>>, [], body}, state) ->
3349
{ bs_parts, collection } = Enum.map_reduce(body, nil, fn
@@ -38,15 +54,41 @@ defmodule ElixirScript.Translator.For do
3854
end)
3955

4056
{ patterns, params, env } = PatternMatching.process_match([{:<<>>, [], bs_parts}], env)
41-
list = Primitive.make_list_no_translate([hd(patterns), Translator.translate!(collection, env)])
42-
%{state | collections: state.collections ++ [list], args: state.args ++ params }
57+
58+
gen = JS.call_expression(
59+
JS.member_expression(
60+
JS.member_expression(
61+
JS.member_expression(
62+
JS.identifier("Elixir"),
63+
JS.identifier("Core")
64+
),
65+
JS.identifier("Patterns")
66+
),
67+
JS.identifier("bitstring_generator")
68+
),
69+
[hd(patterns), Translator.translate!(collection, env)]
70+
)
71+
72+
%{state | generators: state.generators ++ [gen], args: state.args ++ params, patterns: state.patterns ++ patterns }
4373

4474
({:<-, _, [identifier, enum]}, state) ->
4575
{ patterns, params, env } = PatternMatching.process_match([identifier], env)
4676

47-
list = Primitive.make_list_no_translate([hd(patterns), Translator.translate!(enum, env)])
48-
49-
%{state | collections: state.collections ++ [list], args: state.args ++ params }
77+
gen = JS.call_expression(
78+
JS.member_expression(
79+
JS.member_expression(
80+
JS.member_expression(
81+
JS.identifier("Elixir"),
82+
JS.identifier("Core")
83+
),
84+
JS.identifier("Patterns")
85+
),
86+
JS.identifier("list_generator")
87+
),
88+
[hd(patterns), Translator.translate!(enum, env)]
89+
)
90+
91+
%{state | generators: state.generators ++ [gen], args: state.args ++ params, patterns: state.patterns ++ patterns }
5092
([into: expression], state) ->
5193
%{ state | into: Translator.translate(expression, env) }
5294

package.json

Lines changed: 2 additions & 2 deletions
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.2.0"
24+
"tailored": "2.3.1"
2525
},
2626
"devDependencies": {
2727
"babel": "^6.5.2",
@@ -41,4 +41,4 @@
4141
"rollup-plugin-babel": "^2.5.1",
4242
"rollup-plugin-node-resolve": "^1.7.0"
4343
}
44-
}
44+
}

src/javascript/lib/core/special_forms.js

Lines changed: 66 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,145 @@
1-
import Core from '../core';
1+
import Core from "../core";
22

3-
function _case(condition, clauses){
3+
function _case(condition, clauses) {
44
return Core.Patterns.defmatch(...clauses)(condition);
55
}
66

7-
function cond(clauses){
8-
for(let clause of clauses){
9-
if(clause[0]){
7+
function cond(clauses) {
8+
for (let clause of clauses) {
9+
if (clause[0]) {
1010
return clause[1]();
1111
}
1212
}
1313

1414
throw new Error();
1515
}
1616

17-
function map_update(map, values){
17+
function map_update(map, values) {
1818
return Object.freeze(
19-
Object.assign(
20-
Object.create(map.constructor.prototype), map, values
21-
)
19+
Object.assign(Object.create(map.constructor.prototype), map, values)
2220
);
2321
}
2422

25-
function _for(collections, fun, filter = () => true, into = [], previousValues = []){
26-
let pattern = collections[0][0];
27-
let collection = collections[0][1];
23+
function _for(expression, generators, into = []) {
24+
const generatedValues = run_list_generators(generators.pop()(), generators);
2825

29-
if(collections.length === 1){
30-
if(collection instanceof Core.BitString){
31-
let bsSlice = collection.slice(0, pattern.byte_size());
32-
let i = 1;
26+
let result = into;
3327

34-
while(bsSlice.byte_size == pattern.byte_size()){
35-
let r = Core.Patterns.match_or_default(pattern, bsSlice);
36-
let args = previousValues.concat(r);
37-
38-
if(r && filter.apply(this, args)){
39-
into = into.concat([fun.apply(this, args)]);
40-
}
41-
42-
bsSlice = collection.slice(pattern.byte_size() * i, pattern.byte_size() * (i + 1));
43-
i++;
44-
}
45-
46-
return into;
47-
}else{
48-
for(let elem of collection){
49-
let r = Core.Patterns.match_or_default(pattern, elem);
50-
let args = previousValues.concat(r);
51-
52-
if(r && filter.apply(this, args)){
53-
into = into.concat([fun.apply(this, args)]);
54-
}
55-
}
56-
57-
return into;
28+
for (let value of generatedValues) {
29+
if (expression.guard.apply(this, value)) {
30+
result = result.concat([expression.fn.apply(this, value)]);
5831
}
59-
}else{
60-
let _into = [];
61-
62-
if(collection instanceof Core.BitString){
63-
let bsSlice = collection.slice(0, pattern.byte_size());
64-
let i = 1;
32+
}
6533

66-
while(bsSlice.byte_size == pattern.byte_size()){
67-
let r = Core.Patterns.match_or_default(pattern, bsSlice);
68-
if(r){
69-
_into = into.concat(this._for(collections.slice(1), fun, filter, _into, previousValues.concat(r)));
70-
}
34+
return result;
35+
}
7136

72-
bsSlice = collection.slice(pattern.byte_size() * i, pattern.byte_size() * (i + 1));
73-
i++;
37+
function run_list_generators(generator, generators) {
38+
if (generators.length == 0) {
39+
return generator.map(x => {
40+
if (Array.isArray(x)) {
41+
return x;
42+
} else {
43+
return [x];
7444
}
75-
}else{
76-
for(let elem of collection){
77-
let r = Core.Patterns.match_or_default(pattern, elem);
78-
if(r){
79-
_into = into.concat(this._for(collections.slice(1), fun, filter, _into, previousValues.concat(r)));
80-
}
45+
});
46+
} else {
47+
const list = generators.pop();
48+
49+
let next_gen = [];
50+
for (let j of list()) {
51+
for (let i of generator) {
52+
next_gen.push([j].concat(i));
8153
}
8254
}
8355

84-
return _into;
56+
return run_list_generators(next_gen, generators);
8557
}
8658
}
8759

88-
function _try(do_fun, rescue_function, catch_fun, else_function, after_function){
60+
function _try(
61+
do_fun,
62+
rescue_function,
63+
catch_fun,
64+
else_function,
65+
after_function
66+
) {
8967
let result = null;
9068

91-
try{
69+
try {
9270
result = do_fun();
93-
}catch(e){
71+
} catch (e) {
9472
let ex_result = null;
9573

96-
if(rescue_function){
97-
try{
74+
if (rescue_function) {
75+
try {
9876
ex_result = rescue_function(e);
9977
return ex_result;
100-
}catch(ex){
101-
if(ex instanceof Core.Patterns.MatchError){
78+
} catch (ex) {
79+
if (ex instanceof Core.Patterns.MatchError) {
10280
throw ex;
10381
}
10482
}
10583
}
10684

107-
if(catch_fun){
108-
try{
85+
if (catch_fun) {
86+
try {
10987
ex_result = catch_fun(e);
11088
return ex_result;
111-
}catch(ex){
112-
if(ex instanceof Core.Patterns.MatchError){
89+
} catch (ex) {
90+
if (ex instanceof Core.Patterns.MatchError) {
11391
throw ex;
11492
}
11593
}
11694
}
11795

11896
throw e;
119-
120-
}finally{
121-
if(after_function){
97+
} finally {
98+
if (after_function) {
12299
after_function();
123100
}
124101
}
125102

126-
if(else_function){
127-
try{
103+
if (else_function) {
104+
try {
128105
return else_function(result);
129-
}catch(ex){
130-
if(ex instanceof Core.Patterns.MatchError){
131-
throw new Error("No Match Found in Else");
132-
}
106+
} catch (ex) {
107+
if (ex instanceof Core.Patterns.MatchError) {
108+
throw new Error("No Match Found in Else");
109+
}
133110

134111
throw ex;
135112
}
136-
}else{
113+
} else {
137114
return result;
138115
}
139116
}
140117

141-
function _with(...args){
118+
function _with(...args) {
142119
let argsToPass = [];
143120
let successFunction = null;
144121
let elseFunction = null;
145122

146-
if(typeof(args[args.length - 2]) === 'function'){
123+
if (typeof args[args.length - 2] === "function") {
147124
[successFunction, elseFunction] = args.splice(-2);
148-
}else{
125+
} else {
149126
successFunction = args.pop();
150127
}
151128

152-
for(let i = 0; i < args.length; i++){
129+
for (let i = 0; i < args.length; i++) {
153130
let [pattern, func] = args[i];
154131

155132
let result = func.apply(null, argsToPass);
156133

157134
let patternResult = Core.Patterns.match_or_default(pattern, result);
158135

159-
if(patternResult == null){
160-
if(elseFunction){
136+
if (patternResult == null) {
137+
if (elseFunction) {
161138
return elseFunction.call(null, result);
162-
}else{
139+
} else {
163140
return result;
164141
}
165-
}else{
142+
} else {
166143
argsToPass = argsToPass.concat(patternResult);
167144
}
168145
}

0 commit comments

Comments
 (0)