Skip to content

Commit cd9001d

Browse files
committed
Make receive a runtime error. Add warning when receive is encountered. Refactor how functions are implemented
1 parent 25adee9 commit cd9001d

File tree

10 files changed

+148
-2183
lines changed

10 files changed

+148
-2183
lines changed

Supported.md

Lines changed: 0 additions & 2006 deletions
This file was deleted.

lib/elixir_script/gen/supported.ex

Lines changed: 0 additions & 165 deletions
This file was deleted.

lib/elixir_script/next/compiler.ex

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ defmodule ElixirScript.Compiler do
3232
|> Map.put(:entry_modules, entry_modules)
3333

3434
options = default_options
35-
IO.inspect options
3635
Map.put(options, :module_formatter, get_module_formatter(options[:format]))
3736
end
3837

lib/elixir_script/next/passes/translate/clause.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ defmodule ElixirScript.Translate.Clause do
9090
[J.return_statement(J.identifier("null"))]
9191
end
9292

93-
defp compile_guard(params, guards, state) do
93+
def compile_guard(params, guards, state) do
9494

9595
guards = guards
9696
|> List.wrap
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
defmodule Example do
22
def start(_, _) do
3-
1 + 1
3+
receive do
4+
{:selector, i, value} when is_integer(i) ->
5+
value
6+
value when is_atom(value) ->
7+
value
8+
_ ->
9+
IO.puts :stderr, "Unexpected message received"
10+
after
11+
5000 ->
12+
IO.puts :stderr, "No message in 5 seconds"
13+
end
414
end
515

616
end

lib/elixir_script/next/passes/translate/form.ex

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
defmodule ElixirScript.Translate.Form do
22
alias ESTree.Tools.Builder, as: J
3-
alias ElixirScript.Translate.Forms.{Bitstring, Match, Call, Try, For, Struct}
3+
alias ElixirScript.Translate.Forms.{Bitstring, Match, Call, Try, For, Struct, Receive}
44
alias ElixirScript.Translate.Functions.{Erlang, Lists, Maps}
55
alias ElixirScript.Translator.Identifier
66
alias ElixirScript.Translate.Clause
7+
require Logger
78

89
@erlang_modules [
910
:erlang,
@@ -133,9 +134,11 @@ defmodule ElixirScript.Translate.Form do
133134
)
134135
end
135136

136-
def compile({:receive, context, _}, _state) do
137+
def compile({:receive, context, [blocks]}, state) do
137138
line = Keyword.get(context, :line, 1)
138-
raise ElixirScript.CompileError, message: "Line: #{line} receive not supported"
139+
{function, arity} = Map.get(state, :function)
140+
Logger.warn "receive not supported, Module: #{inspect state.module}, Function: #{function}/#{arity}, Line: #{line}"
141+
Receive.compile(blocks, state)
139142
end
140143

141144
def compile({:try, _, [blocks]}, state) do
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
defmodule ElixirScript.Translate.Forms.Receive do
2+
@moduledoc false
3+
alias ESTree.Tools.Builder, as: J
4+
5+
def compile(blocks, state) do
6+
receive_block = Keyword.get(blocks, :do)
7+
after_block = Keyword.get(blocks, :after, nil)
8+
9+
receive_function = J.member_expression(
10+
J.member_expression(
11+
J.identifier("Bootstrap"),
12+
J.member_expression(
13+
J.identifier("Core"),
14+
J.identifier("SpecialForms")
15+
)
16+
),
17+
J.identifier("receive")
18+
)
19+
20+
J.call_expression(
21+
receive_function,
22+
[]
23+
)
24+
25+
end
26+
end

lib/elixir_script/next/passes/translate/function.ex

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule ElixirScript.Translate.Function do
22
alias ESTree.Tools.Builder, as: J
33
alias ElixirScript.Translate.Clause
4+
alias ElixirScript.Translate.Forms.Pattern
5+
alias ElixirScript.Translate.Form
46

57
@moduledoc """
68
Translates the given Elixir function AST into the
@@ -20,18 +22,108 @@ defmodule ElixirScript.Translate.Function do
2022

2123
def compile({{name, arity}, type, _, clauses}, state) do
2224
state = Map.put(state, :function, {name, arity})
25+
clauses = compile_clauses(clauses, state)
26+
27+
arg_matches_declarator = J.variable_declarator(
28+
J.identifier("__arg_matches__"),
29+
J.identifier("null")
30+
)
31+
32+
arg_matches_declaration = J.variable_declaration([arg_matches_declarator], :let)
2333

2434
declarator = J.variable_declarator(
2535
ElixirScript.Translator.Identifier.make_function_name(name, arity),
26-
J.call_expression(
36+
J.function_expression(
37+
[J.rest_element(J.identifier("__function_args__"))],
38+
[],
39+
J.block_statement([
40+
arg_matches_declaration,
41+
clauses,
42+
J.throw_statement(
43+
J.call_expression(
44+
J.member_expression(
45+
patterns_ast(),
46+
J.identifier("MatchError")
47+
),
48+
[J.identifier("__function_args__")]
49+
)
50+
)
51+
])
52+
)
53+
)
54+
55+
J.variable_declaration([declarator], :const)
56+
end
57+
58+
defp compile_clauses(clauses, state) do
59+
clauses
60+
|> Enum.map(&compile_clause(&1, state))
61+
|> Enum.map(fn {patterns, params, guards, body} ->
62+
IO.inspect guards
63+
match_or_default_call = J.call_expression(
2764
J.member_expression(
2865
patterns_ast(),
29-
J.identifier("defmatch")
66+
J.identifier("match_or_default")
67+
),
68+
[J.array_expression(patterns), J.identifier("__function_args__"), guards]
69+
)
70+
71+
J.if_statement(
72+
J.binary_expression(
73+
:!==,
74+
J.assignment_expression(:=, J.identifier("__arg_matches__"), match_or_default_call),
75+
J.identifier("null")
3076
),
31-
Enum.map(clauses, &Clause.compile(&1, state))
77+
J.block_statement(body)
3278
)
79+
end)
80+
|> Enum.reverse
81+
|> Enum.reduce(nil, fn
82+
if_ast, nil ->
83+
if_ast
84+
if_ast, ast ->
85+
%{if_ast | alternate: ast}
86+
end)
87+
end
88+
89+
defp compile_clause({ _, args, guards, body}, state) do
90+
{patterns, params} = Pattern.compile(args, state)
91+
guard = Clause.compile_guard(params, guards, state)
92+
93+
body = case body do
94+
nil ->
95+
J.identifier("null")
96+
{:__block__, _, block_body} ->
97+
Enum.map(block_body, &Form.compile(&1, state))
98+
|> List.flatten
99+
b when is_list(b) ->
100+
Enum.map(b, &Form.compile(&1, state))
101+
|> List.flatten
102+
_ ->
103+
Form.compile(body, state)
104+
end
105+
106+
body = Clause.return_last_statement(body)
107+
108+
declarator = J.variable_declarator(
109+
J.array_expression(params),
110+
J.identifier("__arg_matches__")
33111
)
34112

35-
J.variable_declaration([declarator], :const)
113+
declaration = J.variable_declaration([declarator], :const)
114+
115+
body = [declaration] ++ body
116+
{patterns, params, guard, body}
117+
end
118+
119+
defp compile_clause({:->, _, [[{:when, _, params}], body ]}, state) do
120+
guards = List.last(params)
121+
params = params |> Enum.reverse |> tl |> Enum.reverse
122+
123+
compile_clause({[], params, guards, body}, state)
124+
end
125+
126+
defp compile_clause({:->, _, [params, body]}, state) do
127+
compile_clause({[], params, [], body}, state)
36128
end
37129
end

lib/elixir_script/next/passes/translate/module.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ defmodule ElixirScript.Translate.Module do
2626
} = info
2727

2828
state = %{
29+
module: module,
2930
pid: pid
3031
}
3132

0 commit comments

Comments
 (0)