Skip to content

Commit 533b3a6

Browse files
committed
Moved cond and try implementations to JavaScript
1 parent 5924bef commit 533b3a6

File tree

8 files changed

+217
-179
lines changed

8 files changed

+217
-179
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@ The following aren't defined (yet):
159159
The following are defined but incomplete:
160160

161161
* quote - Currently ignores `:location` and `:context` options
162-
* try - Missing an implementation for the `else` block
163162
* bitstring - Implemented, but no pattern matching support yet
164163

165164
#### Most of the Standard Library isn't defined yet

lib/elixir_script/translator/cond.ex

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,32 @@ defmodule ElixirScript.Translator.Cond do
33

44
alias ESTree.Tools.Builder, as: JS
55
alias ElixirScript.Translator
6+
alias ElixirScript.Translator.Primitive
67
alias ElixirScript.Translator.Function
78
alias ElixirScript.Translator.Utils
89

910
def make_cond(clauses, env) do
10-
process_cond(clauses, nil, env)
11-
|> Utils.wrap_in_function_closure()
11+
JS.call_expression(
12+
JS.member_expression(
13+
JS.member_expression(
14+
JS.identifier("Kernel"),
15+
JS.identifier("SpecialForms")
16+
),
17+
JS.identifier("cond")
18+
),
19+
process_cond(clauses, env)
20+
)
1221
end
1322

14-
defp process_cond([], ast, env) do
15-
ast
16-
end
17-
18-
defp process_cond(clauses, ast, env) do
19-
{:->, _, [clause, clause_body]} = hd(clauses)
20-
21-
translated_body = Translator.translate(clause_body, env)
22-
23-
if translated_body.type != "BlockStatement" do
24-
translated_body = JS.block_statement([translated_body])
25-
end
26-
27-
translated_body = JS.block_statement(Utils.inflate_groups(translated_body.body))
28-
translated_body = Function.return_last_expression(translated_body)
23+
defp process_cond(clauses, env) do
24+
Enum.map(clauses, fn({:->, _, [clause, clause_body]}) ->
25+
translated_body = Function.prepare_function_body(clause_body, env) |> JS.block_statement
26+
function = JS.function_expression([], [], translated_body)
27+
translated_clause = Translator.translate(hd(clause), env)
2928

30-
if hd(clause) == true do
31-
translated_body
32-
else
33-
ast = JS.if_statement(
34-
Translator.translate(hd(clause), env),
35-
translated_body,
36-
nil
37-
)
3829

39-
%ESTree.IfStatement{ ast | alternate: process_cond(tl(clauses), nil, env) }
40-
end
30+
Primitive.make_list_no_translate([translated_clause, function])
31+
end)
4132
end
4233

4334
end

lib/elixir_script/translator/try.ex

Lines changed: 47 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,58 @@ defmodule ElixirScript.Translator.Try do
1010

1111
def make_try(blocks, env) do
1212
try_block = Dict.get(blocks, :do)
13-
rescue_block = Dict.get(blocks, :rescue)
14-
catch_block = Dict.get(blocks, :catch)
15-
after_block = Dict.get(blocks, :after)
16-
else_block = Dict.get(blocks, :else)
13+
rescue_block = Dict.get(blocks, :rescue, nil)
14+
catch_block = Dict.get(blocks, :catch, nil)
15+
after_block = Dict.get(blocks, :after, nil)
16+
else_block = Dict.get(blocks, :else, nil)
17+
18+
translated_body = Function.prepare_function_body(try_block, env) |> JS.block_statement
19+
try_block = JS.function_expression([], [], translated_body)
20+
21+
if rescue_block do
22+
rescue_block = process_rescue_block(rescue_block, env)
23+
else
24+
rescue_block = JS.identifier(:null)
25+
end
1726

18-
if(else_block != nil) do
19-
raise ElixirScript.UnsupportedError, "try with else block"
27+
if catch_block do
28+
catch_block = process_catch_block(catch_block, env)
29+
else
30+
catch_block = JS.identifier(:null)
2031
end
2132

22-
processed_rescue_and_catch_blocks = process_rescue_and_catch(
23-
process_rescue_block(rescue_block),
24-
process_catch_block(catch_block),
25-
env
26-
)
33+
if after_block do
34+
after_block = process_after_block(after_block, env)
35+
else
36+
after_block = JS.identifier(:null)
37+
end
2738

28-
the_catch = case processed_rescue_and_catch_blocks do
29-
nil ->
30-
nil
31-
blocks ->
32-
JS.catch_clause(@error_identifier,
33-
JS.block_statement(List.wrap(blocks))
34-
)
39+
if else_block do
40+
else_block = Function.make_anonymous_function(else_block, env)
41+
else
42+
else_block = JS.identifier(:null)
3543
end
3644

37-
Utils.wrap_in_function_closure(
38-
JS.try_statement(
39-
Function.return_last_expression(
40-
JS.block_statement(List.wrap(Translator.translate(try_block, env)))
45+
JS.call_expression(
46+
JS.member_expression(
47+
JS.member_expression(
48+
JS.identifier("Kernel"),
49+
JS.identifier("SpecialForms")
4150
),
42-
the_catch,
43-
Function.return_last_expression(process_after_block(after_block, env))
44-
)
51+
JS.identifier("_try")
52+
),
53+
[
54+
try_block,
55+
rescue_block,
56+
catch_block,
57+
else_block,
58+
after_block
59+
]
4560
)
46-
end
4761

48-
defp process_rescue_block(nil) do
49-
[]
5062
end
5163

52-
defp process_rescue_block(rescue_block) do
64+
defp process_rescue_block(rescue_block, env) do
5365
Enum.map(rescue_block, fn(x) ->
5466
case x do
5567
{:->, _, [[{value, _, module}], block]} when not is_list(module) ->
@@ -69,34 +81,17 @@ defmodule ElixirScript.Translator.Try do
6981
end
7082
end)
7183
|> List.flatten
84+
|> Function.make_anonymous_function(env)
7285
end
7386

74-
defp process_after_block(nil, _) do
75-
nil
76-
end
77-
78-
defp process_after_block(after_block, env) do
79-
JS.block_statement(List.wrap(
80-
Translator.translate(after_block, env)
81-
))
82-
end
83-
84-
defp process_catch_block(nil) do
85-
[]
86-
end
87-
88-
defp process_catch_block(catch_block) do
87+
defp process_catch_block(catch_block, env) do
8988
catch_block
89+
|> Function.make_anonymous_function(env)
9090
end
9191

92-
def process_rescue_and_catch([], [], _) do
93-
nil
94-
end
95-
96-
def process_rescue_and_catch(processed_rescue_block, processed_catch_block, env) do
97-
processed_clauses = processed_catch_block ++ processed_rescue_block
98-
processed_clauses = processed_clauses ++ [{:->, [], [[], [quote do: throw(e)]]}]
99-
Case.make_case({:e, [], __MODULE__}, processed_clauses, env)
92+
defp process_after_block(after_block, env) do
93+
translated_body = Function.prepare_function_body(after_block, env) |> JS.block_statement
94+
JS.function_expression([], [], translated_body)
10095
end
10196

10297
defp convert_to_struct([module]) do

priv/javascript/lib/kernel/special_forms.js

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ let SpecialForms = {
4040
cond: function(clauses){
4141
for(let clause of clauses){
4242
if(clause[0]){
43-
return clause[1];
43+
return clause[1]();
4444
}
4545
}
4646

@@ -123,6 +123,60 @@ let SpecialForms = {
123123

124124
tuple: function(...args){
125125
return new Tuple(...args);
126+
},
127+
128+
129+
_try: function(do_fun, rescue_function, catch_fun, else_function, after_function){
130+
let result = null;
131+
132+
try{
133+
result = do_fun();
134+
}catch(e){
135+
let ex_result = null;
136+
137+
if(rescue_function){
138+
try{
139+
ex_result = rescue_function(e);
140+
return ex_result;
141+
}catch(ex){
142+
if(ex instanceof Patterns.MatchError){
143+
throw ex;
144+
}
145+
}
146+
}
147+
148+
if(catch_fun){
149+
try{
150+
ex_result = catch_fun(e);
151+
return ex_result;
152+
}catch(ex){
153+
if(ex instanceof Patterns.MatchError){
154+
throw ex;
155+
}
156+
}
157+
}
158+
159+
throw e;
160+
161+
}finally{
162+
if(after_function){
163+
after_function();
164+
}
165+
}
166+
167+
if(else_function){
168+
try{
169+
return else_function(result);
170+
}catch(ex){
171+
if(ex instanceof Patterns.MatchError){
172+
throw new Error("No Match Found in Else");
173+
}
174+
175+
throw ex;
176+
}
177+
}else{
178+
return result;
179+
}
126180
}
127181

128182
};

priv/javascript/tests/cond.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ describe('cond', () => {
88

99
it('cond', () => {
1010
let clauses = [
11-
[ 1 + 1 == 1, "This will never match"],
12-
[ 2 * 2 != 4, "Nor this"],
13-
[ true, "This will"],
11+
[ 1 + 1 == 1, () => "This will never match"],
12+
[ 2 * 2 != 4, () => "Nor this"],
13+
[ true, () => "This will"],
1414
];
1515

1616
let result = Kernel.SpecialForms.cond(clauses);

priv/javascript/tests/try.spec.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
var Patterns = require("../lib/patterns/patterns");
2+
var Enum = require('../lib/enum');
3+
var Kernel = require('../lib/kernel');
4+
var expect = require('chai').expect;
5+
6+
7+
describe('try', () => {
8+
9+
it('try', () => {
10+
/*
11+
try do
12+
1 / x
13+
else
14+
y when y < 1 and y > -1 ->
15+
:small
16+
_ ->
17+
:large
18+
end
19+
20+
*/
21+
22+
let x = 1;
23+
24+
let value = Kernel.SpecialForms._try(function() {
25+
return 1 / x;
26+
}, null, null, Patterns.defmatch(Patterns.make_case([Patterns.variable()], function(y) {
27+
return Kernel.SpecialForms.atom('small');
28+
}, function(y) {
29+
return (y < 1) && (y > -1);
30+
}), Patterns.make_case([Patterns.wildcard()], function() {
31+
return Kernel.SpecialForms.atom('large');
32+
})), null)
33+
34+
expect(value).to.equal(Kernel.SpecialForms.atom('large'));
35+
});
36+
37+
});

test/translator/cond_test.exs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ defmodule ElixirScript.Translator.Cond.Test do
1515
end
1616

1717
js_code = """
18-
(function(){
19-
if(1 + 1 == 1){
20-
return 'This will never match';
21-
}else if(2 * 2 != 4){
22-
return 'Nor this';
23-
}else{
24-
return 'This will';
25-
}
26-
}.call(this))
18+
Kernel.SpecialForms.cond(Kernel.SpecialForms.list(1 + 1 == 1,function() {
19+
return 'This will never match';
20+
}),Kernel.SpecialForms.list(2 * 2 != 4,function() {
21+
return 'Nor this';
22+
}),Kernel.SpecialForms.list(true,function() {
23+
return 'This will';
24+
}))
2725
"""
2826

2927
assert_translation(ex_ast, js_code)
@@ -43,18 +41,16 @@ defmodule ElixirScript.Translator.Cond.Test do
4341
end
4442

4543
js_code = """
46-
(function() {
47-
if(1 + 1 == 1) {
44+
Kernel.SpecialForms.cond(Kernel.SpecialForms.list(1 + 1 == 1,function() {
4845
let [a] = Patterns.match(Patterns.variable(),1);
4946
return 'This will never match';
50-
} else if(2 * 2 != 4) {
51-
let [a] = Patterns.match(Patterns.variable(),2);
52-
return 'Nor this';
53-
} else {
54-
let [a] = Patterns.match(Patterns.variable(),3);
55-
return 'This will';
56-
}
57-
}.call(this))
47+
}),Kernel.SpecialForms.list(2 * 2 != 4,function() {
48+
let [a] = Patterns.match(Patterns.variable(),2);
49+
return 'Nor this';
50+
}),Kernel.SpecialForms.list(true,function() {
51+
let [a] = Patterns.match(Patterns.variable(),3);
52+
return 'This will';
53+
}))
5854
"""
5955

6056
assert_translation(ex_ast, js_code)

0 commit comments

Comments
 (0)