Skip to content

Commit 5ea4512

Browse files
committed
Implement with special form
1 parent b78aa0c commit 5ea4512

9 files changed

Lines changed: 130 additions & 10 deletions

File tree

.tool-versions

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
erlang 20.0
2-
elixir ref-v1.5.0-rc.0
3-
nodejs 8.1.0
2+
elixir ref-v1.5.0-rc.1
3+
nodejs 8.1.0

lib/elixir_script/passes/find_used_functions.ex

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,29 @@ defmodule ElixirScript.FindUsedFunctions do
216216
Enum.each(clauses, &walk(&1, state))
217217
end
218218

219+
defp walk({:with, _, args}, state) do
220+
Enum.each(args, fn
221+
{:<-, _, [left, right]} ->
222+
walk(left, state)
223+
walk(right, state)
224+
225+
{:=, _, [left, right]} ->
226+
walk(left, state)
227+
walk(right, state)
228+
229+
[do: expression] ->
230+
walk_block(expression, state)
231+
232+
[do: expression, else: elses] ->
233+
walk_block(expression, state)
234+
Enum.each(elses, fn
235+
{:->, _, [left, right]} ->
236+
walk(left, state)
237+
walk(right, state)
238+
end)
239+
end)
240+
end
241+
219242
defp walk({{:., _, [:erlang, :apply]}, _, [module, function, params]}, state) do
220243
walk({{:., [], [module, function]}, [], params}, state)
221244
end
@@ -272,4 +295,4 @@ defmodule ElixirScript.FindUsedFunctions do
272295
end
273296
end
274297

275-
end
298+
end

lib/elixir_script/passes/find_used_modules.ex

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,29 @@ defmodule ElixirScript.FindUsedModules do
234234
Enum.each(clauses, &walk(&1, state))
235235
end
236236

237+
defp walk({:with, _, args}, state) do
238+
Enum.each(args, fn
239+
{:<-, _, [left, right]} ->
240+
walk(left, state)
241+
walk(right, state)
242+
243+
{:=, _, [left, right]} ->
244+
walk(left, state)
245+
walk(right, state)
246+
247+
[do: expression] ->
248+
walk_block(expression, state)
249+
250+
[do: expression, else: elses] ->
251+
walk_block(expression, state)
252+
Enum.each(elses, fn
253+
{:->, _, [left, right]} ->
254+
walk(left, state)
255+
walk(right, state)
256+
end)
257+
end)
258+
end
259+
237260
defp walk({{:., _, [:erlang, :apply]}, _, [module, function, params]}, state) do
238261
walk({{:., [], [module, function]}, [], params}, state)
239262
end
@@ -289,4 +312,4 @@ defmodule ElixirScript.FindUsedModules do
289312
end
290313
end
291314

292-
end
315+
end

lib/elixir_script/passes/translate/form.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
defmodule ElixirScript.Translate.Form do
22
alias ESTree.Tools.Builder, as: J
3-
alias ElixirScript.Translate.Forms.{Bitstring, Match, Try, For, Receive, Remote, Pattern}
3+
alias ElixirScript.Translate.Forms.{Bitstring, Match, Try, For, Receive, Remote, Pattern, With}
44
alias ElixirScript.Translate.Clause
55
require Logger
66

@@ -203,6 +203,10 @@ defmodule ElixirScript.Translate.Form do
203203
Try.compile(blocks, state)
204204
end
205205

206+
def compile({:with, _, args}, state) do
207+
With.compile(args, state)
208+
end
209+
206210
def compile({:fn, _, _} = ast, state) do
207211
ElixirScript.Translate.Function.compile(ast, state)
208212
end
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
defmodule ElixirScript.Translate.Forms.With do
2+
@moduledoc false
3+
alias ESTree.Tools.Builder, as: JS
4+
alias ElixirScript.Translate.{Function, Clause}
5+
alias ElixirScript.Translate.Forms.Pattern
6+
7+
8+
def compile(args, module_state) do
9+
result = Enum.reduce(args, %{ expressions: [], arguments: [], module_state: module_state }, fn
10+
{symbol, _, [pattern, body] }, state when symbol in [:<-, :=] ->
11+
{ast, module_state} = Function.compile_block(body, state.module_state)
12+
body = Clause.return_last_statement(ast)
13+
expr_function = JS.arrow_function_expression(state.arguments, [], JS.block_statement(body))
14+
15+
{ patterns, params, module_state } = Pattern.compile([pattern], module_state)
16+
17+
%{state | arguments: state.arguments ++ params,
18+
expressions: state.expressions ++ [ JS.array_expression([hd(patterns), expr_function]) ],
19+
module_state: module_state
20+
}
21+
22+
[do: expr], state ->
23+
expr_function = process_block(expr, state.arguments, state.module_state)
24+
25+
%{state | expressions: state.expressions ++ [ expr_function ] }
26+
[do: do_expr, else: else_expr], state ->
27+
do_function = process_block(do_expr, state.arguments, state.module_state)
28+
29+
{ else_function, _ } = Function.compile({:fn, [], else_expr}, state.module_state)
30+
31+
%{state | expressions: state.expressions ++ [ do_function, else_function ] }
32+
end)
33+
34+
expressions = result.expressions
35+
36+
js_ast = JS.call_expression(
37+
JS.member_expression(
38+
JS.member_expression(
39+
JS.identifier("Bootstrap"),
40+
JS.member_expression(
41+
JS.identifier("Core"),
42+
JS.identifier("SpecialForms")
43+
)
44+
),
45+
JS.identifier("_with")
46+
),
47+
expressions
48+
)
49+
50+
{ js_ast, module_state }
51+
52+
end
53+
54+
55+
defp process_block(body, arguments, module_state) do
56+
{ast, _} = Function.compile_block(body, module_state)
57+
58+
body = Clause.return_last_statement(ast)
59+
JS.arrow_function_expression(arguments, [], JS.block_statement(body))
60+
end
61+
end

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@
4141
"sinon": "^1.17.7"
4242
},
4343
"ava": {
44-
"require": [
45-
"babel-register"
46-
],
44+
"require": ["babel-register"],
4745
"babel": {
4846
"babelrc": true
4947
}

src/javascript/lib/core/special_forms.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,5 @@ export default {
151151
_for,
152152
_try,
153153
_with,
154-
receive,
154+
receive
155155
};

src/javascript/tests/with.spec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Core from '../lib/core';
22
import test from 'ava';
3+
34
const Patterns = Core.Patterns;
45
const SpecialForms = Core.SpecialForms;
56
const Tuple = Core.Tuple;
@@ -78,7 +79,7 @@ test('with bare expression', t => {
7879
[$, width => width * 2],
7980
[
8081
new Tuple(Symbol.for('ok'), $),
81-
(width, double_width) => map_fetch(opts, 'height'),
82+
(width, double_width) => map_fetch(opts, 'height')
8283
],
8384
(width, double_width, height) =>
8485
new Tuple(Symbol.for('ok'), double_width * height)

test/support/main.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
defmodule Main do
22
def start(:normal, [callback]) do
33
callback.("started")
4+
5+
opts = %{width: 10, height: 15}
6+
with {:ok, width} <- Map.fetch(opts, :width),
7+
{:ok, height} <- Map.fetch(opts, :height)
8+
do
9+
{:ok, width * height}
10+
else
11+
:error ->
12+
{:error, :wrong_data}
13+
end
414
end
515
end

0 commit comments

Comments
 (0)