Last active
May 8, 2019 22:21
-
-
Save alco/6449190 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
iex> """ |> Erlang.module_to_core |> IO.puts | |
...> -file("nofile", 1). | |
...> -module('Elixir.M'). | |
...> | |
...> -export([hello/0]). | |
...> | |
...> hello() -> hello. | |
...> """ | |
module 'Elixir.M' ['hello'/0, | |
'module_info'/0, | |
'module_info'/1] | |
attributes [] | |
'hello'/0 = | |
%% Line 6 | |
fun () -> | |
'hello' | |
'module_info'/0 = | |
fun () -> | |
call 'erlang':'get_module_info' | |
('Elixir.M') | |
'module_info'/1 = | |
fun (_cor0) -> | |
call 'erlang':'get_module_info' | |
('Elixir.M', _cor0) | |
end | |
:ok |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Erlang do | |
@doc """ | |
Receives a module definition (a string or a quoted expression), compiles it, | |
and returns a string with pretty printed Erlang code. | |
""" | |
def module_to_code(string) when is_binary(string) do | |
to_code_dispatch(Code.eval_string(string)) | |
end | |
def module_to_code(q) do | |
to_code_dispatch(Code.eval_quoted(q)) | |
end | |
@doc """ | |
Receives an expression (string or quote) and produces pretty-printed Erlang | |
code out of it. | |
""" | |
def expr_to_code(string) when is_binary(string) do | |
code = String.to_char_list!(string) | |
forms = :elixir_translator.forms!(code, 1, "nofile", []) | |
pretty_print_forms(forms) | |
end | |
def expr_to_code(q) do | |
pretty_print_forms([q]) | |
end | |
@doc """ | |
Compiles given Erlang module definition to Core Erlang. | |
""" | |
def module_to_core(string) when is_binary(string) do | |
{ :ok, tokens, _ } = :erl_scan.string(String.to_char_list!(string)) | |
{ :ok, module, core } | |
= tokens | |
|> Enum.chunks_by(&match?({:dot, _}, &1)) | |
|> Stream.filter(¬ match?([{:dot, _}], &1)) | |
|> Enum.map(fn tf -> | |
{ :ok, form } = :erl_parse.parse_form(tf ++ [{:dot,-1}]) | |
form | |
end) | |
|> :compile.forms(:to_core) | |
String.from_char_list!(:core_pp.format(core)) | |
end | |
### Private helpers | |
defp to_code_dispatch(code) do | |
case code do | |
{ {:module,_,beam_code,_}, _ } -> | |
pretty_print_beam(beam_code) | |
end | |
end | |
defp pretty_print_beam(beam_code) do | |
{:ok, {_, [{:abstract_code, {_, code}}]}} | |
= :beam_lib.chunks(beam_code, [:abstract_code]) | |
String.from_char_list!(:erl_prettypr.format(:erl_syntax.form_list(code))) | |
end | |
defp pretty_print_forms(forms) do | |
scope = :elixir.scope_for_eval(file: "nofile") | |
{ exprs, _ } = :elixir_translator.translate(forms, scope) | |
String.from_char_list!(:erl_prettypr.format(:erl_syntax.form_list(exprs))) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
iex> Erlang.expr_to_code("File.Stat[]") |> IO.puts | |
{'Elixir.File.Stat', undefined, undefined, undefined, | |
undefined, undefined, undefined, undefined, undefined, | |
undefined, undefined, undefined, undefined, undefined} | |
:ok | |
iex> Erlang.module_to_code(quote do | |
...> defmodule MM do | |
...> def hello, do: :hello | |
...> end | |
...> end) |> IO.puts | |
-compile({no_auto_import, | |
[{bitsize, 1}, {apply, 2}, {spawn, 2}, {spawn_link, 2}, | |
{spawn_monitor, 3}, {spawn_opt, 2}, {spawn_opt, 3}, | |
{spawn, 4}, {spawn_link, 4}, {spawn_opt, 4}, | |
{spawn_opt, 5}, {nodes, 0}, {disconnect_node, 1}, | |
{integer_to_list, 2}, {integer_to_binary, 2}, {max, 2}, | |
{min, 2}, {port_control, 3}, {port_connect, 2}, | |
{port_command, 2}, {port_command, 3}, {port_close, 1}, | |
{spawn_monitor, 1}, {spawn, 1}, {load_module, 2}, | |
{spawn_link, 1}, {binary_to_float, 1}, | |
{float_to_binary, 2}, {float_to_binary, 1}, | |
{list_to_integer, 2}, {integer_to_binary, 1}, | |
{binary_to_integer, 2}, {binary_to_integer, 1}, | |
{check_old_code, 1}, {binary_part, 3}, {binary_part, 2}, | |
{binary_to_term, 2}, {binary_to_existing_atom, 2}, | |
{binary_to_atom, 2}, {atom_to_binary, 2}, | |
{bitstring_to_list, 1}, {list_to_bitstring, 1}, | |
{bit_size, 1}, {byte_size, 1}, {tuple_size, 1}, | |
{is_bitstring, 1}, {list_to_existing_atom, 1}, | |
{iolist_to_binary, 1}, {iolist_size, 1}, | |
{is_boolean, 1}, {is_record, 3}, {is_record, 2}, | |
{is_function, 2}, {is_function, 1}, {is_binary, 1}, | |
{is_reference, 1}, {is_port, 1}, {is_pid, 1}, | |
{is_number, 1}, {is_integer, 1}, {is_float, 1}, | |
{is_tuple, 1}, {is_list, 1}, {is_atom, 1}, {error, 2}, | |
{error, 1}, {is_process_alive, 1}, {demonitor, 2}, | |
{demonitor, 1}, {monitor, 2}, {whereis, 1}, | |
{unregister, 1}, {unlink, 1}, {tuple_to_list, 1}, | |
{trunc, 1}, {tl, 1}, {time, 0}, {throw, 1}, | |
{term_to_binary, 2}, {term_to_binary, 1}, | |
{statistics, 1}, {split_binary, 2}, {spawn_link, 3}, | |
{spawn, 3}, {size, 1}, {setelement, 3}, {self, 0}, | |
{round, 1}, {registered, 0}, {register, 2}, {put, 2}, | |
{purge_module, 1}, {processes, 0}, {process_info, 2}, | |
{process_info, 1}, {process_flag, 3}, {process_flag, 2}, | |
{pre_loaded, 0}, {pid_to_list, 1}, {open_port, 2}, | |
{now, 0}, {nodes, 1}, {node, 0}, {node, 1}, | |
{monitor_node, 2}, {module_loaded, 1}, {make_ref, 0}, | |
{list_to_tuple, 1}, {list_to_pid, 1}, | |
{list_to_integer, 1}, {list_to_float, 1}, | |
{list_to_binary, 1}, {list_to_atom, 1}, {link, 1}, | |
{length, 1}, {is_alive, 0}, {integer_to_list, 1}, | |
{hd, 1}, {halt, 2}, {halt, 1}, {halt, 0}, | |
{group_leader, 2}, {group_leader, 0}, {get_keys, 1}, | |
{get, 1}, {get, 0}, {garbage_collect, 1}, | |
{garbage_collect, 0}, {float_to_list, 2}, | |
{float_to_list, 1}, {float, 1}, {exit, 2}, {exit, 1}, | |
{erase, 1}, {erase, 0}, {element, 2}, | |
{delete_module, 1}, {date, 0}, {check_process_code, 2}, | |
{binary_to_term, 1}, {binary_to_list, 3}, | |
{binary_to_list, 1}, {atom_to_list, 1}, {apply, 3}, | |
{abs, 1}]}). | |
-file("nofile", 1). | |
-module('Elixir.MM'). | |
-export(['__info__'/1, hello/0]). | |
'__info__'(functions) -> [{hello, 0}]; | |
'__info__'(macros) -> []; | |
'__info__'(docs) -> [{{hello, 0}, 1, def, [], nil}]; | |
'__info__'(moduledoc) -> {1, nil}; | |
'__info__'(module) -> 'Elixir.MM'; | |
'__info__'(atom) -> module_info(atom). | |
hello() -> hello. | |
:ok |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment