Elixir into Erlang transformation

前端 未结 2 2039
无人及你
无人及你 2021-01-13 06:07

I want to see what happens when elixir gets transformed into beam files. Is there any way to print in console or in a file how it is translated? I want to know what would th

相关标签:
2条回答
  • 2021-01-13 06:38

    First, you need to compile the Elixir module to a .beam file:

    $ cat test.ex
    defmodule Test do
        def t1(a), do: a
        def t1(a, b \\ 2), do: a + b
    end
    $ elixirc test.ex
    warning: this clause cannot match because a previous clause at line 2 always matches
      test.ex:3
    

    This will generate Elixir.Test.beam. Then, you can decompile this .beam to Erlang source using the following escript (I copied this from some answer here on Stackoverflow a while ago. Unfortunately I can't seem to locate the exact source but this code is in many answers here including this one.):

    $ cat decompile.erl
    #!/usr/bin/env escript
    
    main([BeamFile]) ->
      {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(BeamFile,[abstract_code]),
      io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).
    

    Then run it:

    $ escript decompile.erl Elixir.Test.beam
    -compile(no_auto_import).
    
    -file("test.ex", 1).
    
    -module('Elixir.Test').
    
    -export(['__info__'/1, t1/1, t1/2]).
    
    -spec '__info__'(attributes | compile | exports |
             functions | macros | md5 | module |
             native_addresses) -> atom() |
                          [{atom(), any()} |
                           {atom(), byte(), integer()}].
    
    '__info__'(functions) -> [{t1, 1}, {t1, 2}];
    '__info__'(macros) -> [];
    '__info__'(info) ->
        erlang:get_module_info('Elixir.Test', info).
    
    t1(a@1) -> a@1;
    t1(x0@1) -> t1(x0@1, 2).
    
    t1(a@1, b@1) -> a@1 + b@1.
    
    0 讨论(0)
  • 2021-01-13 06:49

    This probably should be more of a comment to @Dogbert’s answer above, but I would post it as a separate answer for the sake of formatting.

    One does not need to create .ex files and invoke the compiler on them to produce beams:

    {:module, _, bytecode, _} =
      defmodule Elixir.Test do
        def t1(a), do: a
        def t1(a, b \\ 2), do: a + b
      end
    # File.write!("Elixir.Test.beam", bytecode)
    

    now you might have had a beam file written (we have it stored in the bytecode variable by the way.)

    NB: beam_lib:chunks/2 works if and only the beam contains unencrypted debug information (elixir beams by default do.)

    Also, you don’t need to write decompiled erlang code, you might simply pass a binary there, directly in Elixir:

    :beam_lib.chunks(bytecode, [:abstract_code])
    

    To extract the code itself:

    {:ok,{_,[abstract_code: {_, code}]}} = 
       bytecode |> :beam_lib.chunks([:abstract_code])
    

    Now code contains the code, it should be enough to examine it, but you still are free to use erlang build-ins:

    code |> :erl_syntax.form_list
    

    or:

    code |> :erl_syntax.form_list |> :erl_prettypr.format
    

    The latter will give you the binary charlist, containing erlang code, exactly as in @Dogbert’s answer. Use IO.puts to output it.

    0 讨论(0)
提交回复
热议问题