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

Ljzn
407 声望103 粉丝

尽量减少神经质的时间


引用和评论

0 条评论