elixir or erlang or other languages running on beam vm will be compiled into .beam
files. So is it possible to rebuild erlang code from these files? The answer is yes.
[file] = System.argv()
beam = File.read!(file)
{:ok, {_, [{:abstract_code, {_, ac}}]}} = :beam_lib.chunks(beam, [:abstract_code])
out = file <> ".erl"
File.touch!(out)
File.write!(out, :erl_prettypr.format(:erl_syntax.form_list(ac)))
Save the above code as beam2erl.exs
file.
Then we randomly find an elixir file, for example:
defmodule Demo do
defdelegate puts(str), to: IO
end
Compile it, then copy the corresponding beam file to the beam2erl.exs
directory, and then execute:
$ elixir beam2erl.exs Elixir.Demo.beam
You can see that a .erl
file has been generated, the content is:
-file("lib/demo.ex", 1).
-module('Elixir.Demo').
-compile([no_auto_import]).
-export(['__info__'/1, puts/1]).
-spec '__info__'(attributes |
compile |
functions |
macros |
md5 |
exports_md5 |
module |
deprecated) -> any().
'__info__'(module) -> 'Elixir.Demo';
'__info__'(functions) -> [{puts, 1}];
'__info__'(macros) -> [];
'__info__'(exports_md5) ->
<<"\n\025Y�a#�x�\201W��a#�">>;
'__info__'(Key = attributes) ->
erlang:get_module_info('Elixir.Demo', Key);
'__info__'(Key = compile) ->
erlang:get_module_info('Elixir.Demo', Key);
'__info__'(Key = md5) ->
erlang:get_module_info('Elixir.Demo', Key);
'__info__'(deprecated) -> [].
puts(_str@1) -> 'Elixir.IO':puts(_str@1).
The long list above is the functions built into the module, and the last line is the content of our code.
With this little script, it's much easier to learn and tweak code that contains complex elixir macros.
can be organized into a function
defmodule M do
defmacro ast_to_erl(ast) do
[{_, beam}] = Code.compile_quoted(ast)
{:ok, {_, [{:abstract_code, {_, ac}}]}} = :beam_lib.chunks(beam, [:abstract_code])
:erl_prettypr.format(:erl_syntax.form_list(ac), encoding: :utf8)
|> IO.puts()
end
end
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。