Skip to content

Commit 88e809a

Browse files
committed
Updated for implementation
1 parent 8d193da commit 88e809a

File tree

21 files changed

+612
-530
lines changed

21 files changed

+612
-530
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ The following are defined but incomplete:
160160

161161
* quote - Currently ignores `:location` and `:context` options
162162
* try - Missing an implementation for the `else` block
163-
* for - `into` not implementated yet
164163
* bitstring - Implemented, but no pattern matching support yet
165164

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

lib/elixir_script/lib/js.ex

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,16 @@ defmodule ElixirScript.Lib.JS do
3535
"""
3636
defmacro import(module, from)
3737

38+
39+
@doc """
40+
Turns an ElixirScript data structure into a JavaScript one.
41+
"""
42+
defmacro to_js(value)
43+
44+
45+
@doc """
46+
Turns an ElixirScript data structure into JSON.
47+
"""
48+
defmacro to_json(value)
49+
3850
end
Lines changed: 56 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -1,197 +1,69 @@
11
defmodule ElixirScript.Translator.For do
22
@moduledoc false
3-
alias ESTree.Tools.Builder
3+
alias ESTree.Tools.Builder, as: JS
44
alias ElixirScript.Translator
55
alias ElixirScript.Translator.Utils
6+
alias ElixirScript.PatternMatching.Match
7+
alias ElixirScript.Translator.Primitive
8+
alias ElixirScript.Translator.Function
69

710

811
def make_for(generators, env) do
9-
quoted = quote do: _results
10-
_results = Translator.translate(quoted, env)
11-
12-
quoted = quote do: _results = []
13-
variable_declaration = Translator.translate(quoted, env)
14-
15-
block_statement = [variable_declaration] ++ [handle_generators(generators, env)] ++ [Builder.return_statement(_results)]
16-
17-
Utils.wrap_in_function_closure(block_statement)
18-
end
19-
20-
defp handle_generators(generators, env) do
21-
22-
case hd(generators) do
23-
{:<-, [], [identifier, enum]} ->
24-
case identifier do
25-
{value_one, value_two} ->
26-
elements = [value_one, value_two]
27-
make_tuple_for(elements, enum, generators, env)
28-
{:{}, _, elements} ->
29-
make_tuple_for(elements, enum, generators, env)
30-
_ ->
31-
i = Translator.translate(identifier, env)
32-
variable_declarator = Builder.variable_declarator(i)
33-
variable_declaration = Builder.variable_declaration([variable_declarator], :let)
34-
35-
Builder.for_of_statement(
36-
variable_declaration,
37-
Translator.translate(enum, env),
38-
Builder.block_statement(List.wrap(handle_generators(tl(generators), env)))
39-
)
40-
end
41-
[into: _expression] ->
42-
raise ElixirScript.UnsupportedError, :into
43-
[do: expression] ->
44-
push_last_expression(Translator.translate(expression, env))
45-
filter ->
46-
Builder.if_statement(
47-
Translator.translate(filter, env),
48-
handle_generators(tl(generators), env),
49-
nil
50-
)
51-
end
52-
53-
end
54-
55-
defp make_tuple_for(elements, enum, generators, env) do
56-
i = Builder.identifier("_ref")
57-
variable_declarator = Builder.variable_declarator(i)
58-
variable_declaration = Builder.variable_declaration([variable_declarator], :let)
59-
60-
{ variables, _ } = Enum.map_reduce(elements, 0,
61-
fn(x, index) ->
62-
case Translator.translate(x, env) do
63-
%ESTree.Identifier{} ->
64-
variable_declarator = Builder.variable_declarator(Translator.translate(x, env),
65-
Builder.call_expression(
66-
Builder.member_expression(
67-
Builder.identifier(:Kernel),
68-
Builder.identifier(:elem)
69-
),
70-
[i, Builder.literal(index)]
71-
)
72-
)
73-
variable_declaration = Builder.variable_declaration([variable_declarator], :let)
74-
75-
{variable_declaration, index + 1}
76-
_ ->
77-
{nil, index + 1}
78-
end
79-
end)
80-
81-
variables = Enum.filter(variables, fn(x) -> x != nil end)
82-
83-
new_identifier = Enum.map(elements, fn(x) ->
84-
case Translator.translate(x, env) do
85-
%ESTree.Identifier{} ->
86-
Builder.identifier(:undefined)
87-
_ ->
88-
Translator.translate(x, env)
89-
end
90-
end)
91-
92-
new_identifier = Builder.call_expression(
93-
Builder.member_expression(
94-
Builder.identifier("Erlang"),
95-
Builder.identifier("tuple")
12+
args = handle_args(generators, env)
13+
14+
collections = Primitive.make_list_no_translate(args.collections)
15+
into = args.into || Primitive.make_list_no_translate([])
16+
filter = args.filter || JS.function_expression([], [], JS.block_statement([JS.return_statement(JS.identifier("true"))]))
17+
fun = args.fun
18+
19+
JS.call_expression(
20+
JS.member_expression(
21+
JS.member_expression(
22+
JS.identifier("Kernel"),
23+
JS.identifier("SpecialForms")
24+
),
25+
JS.identifier("_for")
9626
),
97-
new_identifier
27+
[collections, fun, filter, into]
9828
)
99-
100-
Builder.for_of_statement(
101-
variable_declaration,
102-
Translator.translate(enum, env),
103-
Builder.block_statement(
104-
[
105-
Builder.if_statement(
106-
Utils.make_match(i, new_identifier, env),
107-
Builder.block_statement(variables ++ List.wrap(handle_generators(tl(generators), env)))
108-
)
109-
]
110-
)
111-
)
112-
end
113-
114-
defp push_last_expression(%ESTree.BlockStatement{} = block) do
115-
%ESTree.BlockStatement{ block | body: push_last_expression(block.body) }
116-
end
117-
118-
defp push_last_expression([]) do
119-
build_push_ast(Builder.literal(nil))
12029
end
12130

122-
defp push_last_expression(list) when is_list(list) do
123-
last_item = List.last(list)
124-
125-
last_item = case last_item do
126-
%ESTree.Literal{} ->
127-
build_push_ast(last_item)
128-
%ESTree.Identifier{} ->
129-
build_push_ast(last_item)
130-
%ESTree.VariableDeclaration{} ->
131-
declaration = hd(last_item.declarations).id
132-
133-
push_statement = case declaration do
134-
%ESTree.ArrayPattern{} ->
135-
build_push_ast(Builder.array_expression(declaration.elements))
136-
_ ->
137-
build_push_ast(declaration)
138-
end
139-
140-
[last_item, push_statement]
141-
%ESTree.IfStatement{} ->
142-
143-
consequent = push_last_expression(last_item.consequent)
144-
145-
alternate = if last_item.alternate do
146-
push_last_expression(last_item.alternate)
147-
else
148-
nil
149-
end
150-
151-
last_item = %ESTree.IfStatement{ last_item | consequent: consequent, alternate: alternate }
152-
%ElixirScript.Translator.Group{body: body} ->
153-
last_item = push_last_expression(body)
154-
%ESTree.BlockStatement{} ->
155-
last_item = %ESTree.BlockStatement{ last_item | body: push_last_expression(last_item.body) }
156-
_ ->
157-
if String.contains?(last_item.type, "Expression") do
158-
build_push_ast(last_item)
159-
else
160-
[last_item, build_push_ast(Builder.literal(nil))]
161-
end
162-
end
163-
164-
165-
list = Enum.take(list, length(list)-1)
166-
167-
if is_list(last_item) do
168-
list ++ last_item
169-
else
170-
list ++ [last_item]
171-
end
172-
end
173-
174-
defp push_last_expression(expression) do
175-
build_push_ast(expression)
176-
end
177-
178-
defp build_push_ast(param) do
179-
180-
Builder.expression_statement(
181-
Builder.assignment_expression(
182-
:=,
183-
Builder.identifier(:_results),
184-
Builder.call_expression(
185-
Builder.member_expression(
186-
Builder.identifier("List"),
187-
Builder.identifier("append")
188-
),
189-
[Builder.identifier(:_results), param]
190-
)
191-
)
192-
)
193-
194-
end
31+
defp handle_args(generators, env) do
32+
Enum.reduce(generators, %{collections: [], args: [], filter: nil, fun: nil, into: nil}, fn
33+
({:<-, [], [identifier, enum]}, state) ->
34+
{ patterns, params } = Match.build_match([identifier], env)
35+
36+
list = Primitive.make_list_no_translate([hd(patterns), Translator.translate(enum, env)])
37+
38+
%{state | collections: state.collections ++ [list], args: state.args ++ params }
39+
([into: expression], state) ->
40+
%{ state | into: Translator.translate(expression, env) }
41+
([into: expression, do: expression2], state) ->
42+
fun = JS.function_expression(
43+
state.args,
44+
[],
45+
Function.make_function_body(expression2, env)
46+
)
47+
48+
%{ state | into: Translator.translate(expression, env), fun: fun }
49+
50+
([do: expression], state) ->
51+
52+
fun = JS.function_expression(
53+
state.args,
54+
[],
55+
Function.make_function_body(expression, env)
56+
)
57+
58+
%{ state | fun: fun }
59+
(filter, state) ->
60+
fun = JS.function_expression(
61+
state.args,
62+
[],
63+
Function.make_function_body(filter, env)
64+
)
19565

196-
66+
%{ state | filter: fun }
67+
end)
68+
end
19769
end

lib/elixir_script/translator/function.ex

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,27 @@ defmodule ElixirScript.Translator.Function do
2525
{:->, _, [ [{:when, _, [params | guards]}], body ]} ->
2626
{ patterns, params } = Match.build_match(List.wrap(params), env)
2727
params = make_params(params)
28-
body = make_body(body, env)
28+
body = make_function_body(body, env)
2929
guard_body = make_guards(guards, env)
3030
do_make_function_clause(patterns, params, body, guard_body)
3131

3232
({:->, _, [params, body]}) ->
3333
{ patterns, params } = Match.build_match(params, env)
3434
params = make_params(params)
35-
body = make_body(body, env)
35+
body = make_function_body(body, env)
3636
do_make_function_clause(patterns, params, body)
3737

3838
({_, _, [{:when, _, [{_, _, params} | guards] }, [do: body]]}) ->
3939
{ patterns, params } = Match.build_match(params, env)
4040
params = make_params(params)
41-
body = make_body(body, env)
41+
body = make_function_body(body, env)
4242
guard_body = make_guards(guards, env)
4343
do_make_function_clause(patterns, params, body, guard_body)
4444

4545
({_, _, [{_, _, params}, [do: body]]}) ->
4646
{ patterns, params } = Match.build_match(params, env)
4747
params = make_params(params)
48-
body = make_body(body, env)
48+
body = make_function_body(body, env)
4949
do_make_function_clause(patterns, params, body)
5050

5151
end)
@@ -60,7 +60,7 @@ defmodule ElixirScript.Translator.Function do
6060
)
6161
end
6262

63-
defp make_body(body, env) do
63+
def make_function_body(body, env) do
6464
body
6565
|> prepare_function_body(env)
6666
|> JS.block_statement

lib/elixir_script/translator/js.ex

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,26 @@ defmodule ElixirScript.Translator.JS do
6464
)
6565
end
6666

67+
68+
defp do_translate({:to_js, _, [value]}, env) do
69+
quoted = quote do
70+
if is_list(unquote(value)) || is_map(unquote(value)) || is_tuple(unquote(value)) do
71+
value.toJS()
72+
else
73+
value
74+
end
75+
end
76+
77+
Translator.translate(quoted, env)
78+
end
79+
80+
81+
defp do_translate({:to_json, _, [value]}, env) do
82+
quoted = quote do
83+
JSON.stringify(JS.to_js(unquote(value)))
84+
end
85+
86+
Translator.translate(quoted, env)
87+
end
88+
6789
end

0 commit comments

Comments
 (0)