Skip to content

Commit 8a854b6

Browse files
committed
Add support for super for defoverridable
1 parent 5d3f51f commit 8a854b6

6 files changed

Lines changed: 109 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
66

77
## [0.27.0-dev]
88

9+
### Added
10+
- `super`
11+
- `defoverridable`
12+
913
### Changed
1014
- `-ex` alias is now `-e`
1115
- A filename can be specified for output

FAQ.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ The compiler to this point has been focused on translating Kernel.SpecialForms a
3838
* `alias`
3939
* `__CALLER__`
4040
* `__ENV__`
41+
* `super(args)`
4142

4243
* Missing
43-
* `super(args)`
4444
* `receive`
4545

4646
* Caveats

lib/elixir_script.ex

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,14 @@ defmodule ElixirScript do
7575

7676
%{data: std_lib_quoted ++ data}
7777
|> ElixirScript.Passes.Init.execute(opts)
78+
|> shared_passes(opts)
79+
end
80+
81+
defp shared_passes(compiler_data, opts) do
82+
compiler_data
7883
|> ElixirScript.Passes.FindModules.execute(opts)
7984
|> ElixirScript.Passes.FindLoadOnly.execute(opts)
85+
|> ElixirScript.Passes.HandleOverridables.execute(opts)
8086
|> ElixirScript.Passes.FindFunctions.execute(opts)
8187
|> ElixirScript.Passes.JavaScriptAST.execute(opts)
8288
|> ElixirScript.Passes.ConsolidateProtocols.execute(opts)
@@ -164,14 +170,7 @@ defmodule ElixirScript do
164170
|> ElixirScript.Passes.Init.execute(opts)
165171
|> ElixirScript.Passes.ASTFromFile.execute(opts)
166172
|> ElixirScript.Passes.LoadModules.execute(opts)
167-
|> ElixirScript.Passes.FindModules.execute(opts)
168-
|> ElixirScript.Passes.FindLoadOnly.execute(opts)
169-
|> ElixirScript.Passes.FindFunctions.execute(opts)
170-
|> ElixirScript.Passes.JavaScriptAST.execute(opts)
171-
|> ElixirScript.Passes.ConsolidateProtocols.execute(opts)
172-
|> ElixirScript.Passes.CreateJSModules.execute(opts)
173-
|> ElixirScript.Passes.JavaScriptCode.execute(opts)
174-
|> ElixirScript.Passes.HandleOutput.execute(opts)
173+
|> shared_passes(opts)
175174

176175
result
177176
end
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
defmodule ElixirScript.Passes.HandleOverridables do
2+
@moduledoc false
3+
4+
def execute(compiler_data, opts) do
5+
new_data = Enum.map(compiler_data.data, fn { module_name, module_data } ->
6+
overridables = get_overridables(module_data.ast)
7+
ast = handle_overridable(module_data.ast, overridables)
8+
module_data = Map.put(module_data, :ast, ast)
9+
10+
{module_name, module_data}
11+
end)
12+
13+
Map.put(compiler_data, :data, new_data)
14+
end
15+
16+
defp get_overridables({:__block__, [], body}) do
17+
defover = Enum.find(body, fn
18+
{:defoverridable, _, _} ->
19+
true
20+
_ ->
21+
false
22+
end)
23+
24+
if is_nil(defover) do
25+
[]
26+
else
27+
{:defoverridable, _, [overridables]} = defover
28+
overridables
29+
end
30+
end
31+
32+
defp handle_overridable(ast, []) do
33+
ast
34+
end
35+
36+
defp handle_overridable({:__block__, [], body}, overridables) do
37+
result = body
38+
|> Enum.reduce(%{overridables: [], overridable_found: false, body: []}, fn
39+
{:def, def_context, [{name, context, params}, function_body] } = ast, %{overridable_found: false} = acc ->
40+
Map.put(acc, :overridables, acc.overridables ++ [ast])
41+
42+
{:defoverridable, _, _}, acc ->
43+
Map.put(acc, :overridable_found, true)
44+
x, acc ->
45+
Map.put(acc, :body, acc.body ++ [x])
46+
end)
47+
48+
processed_overridables = Enum.map(result.overridables, fn
49+
{:def, def_context, [{name, context, params}, function_body] } = ast ->
50+
arity = get_arity(params)
51+
52+
found = Enum.any?(result.body, fn
53+
{:def, _, [{name_from_body, _, params_from_body}, _] } ->
54+
if {name, arity} == {name_from_body, get_arity(params_from_body)} do
55+
true
56+
else
57+
false
58+
end
59+
_ ->
60+
false
61+
end)
62+
63+
if found do
64+
super_name = String.to_atom("__super__" <> to_string(name))
65+
{:defp, def_context, [{super_name, context, params}, function_body] }
66+
else
67+
ast
68+
end
69+
end)
70+
71+
body = processed_overridables ++ result.body
72+
{:__block__, [], body}
73+
end
74+
75+
defp get_arity(params) do
76+
cond do
77+
is_nil(params) ->
78+
0
79+
is_atom(params) ->
80+
0
81+
true ->
82+
length(params)
83+
end
84+
end
85+
86+
end

lib/elixir_script/translator.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,13 @@ defmodule ElixirScript.Translator do
243243
{ Map.make_get_property(target, property, env), env }
244244
end
245245

246+
defp do_translate({:super, _, params }, env) do
247+
{ name, _ } = env.function
248+
super_name = String.to_atom("__super__" <> to_string(name))
249+
250+
Call.make_local_function_call(super_name, params, env)
251+
end
252+
246253
defp do_translate({{:., _, [function_name]}, _, params}, env) do
247254
Call.make_local_function_call(function_name, params, env)
248255
end

priv/std_lib/keyword.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
defmodule ElixirScript.Keyword do
22
@moduledoc false
33

4+
def new() do
5+
[]
6+
end
7+
48
def has_key?(kw, key) do
59
do_has_key?(kw, key)
610
end

0 commit comments

Comments
 (0)