Eh, not really like assembler, it is the very definition of AST. Elixir’s AST.
The compilation process goes: Elixir → Elixir’s AST (what quote
gives you) → Erlang (Abstract Format, basically it’s AST) → Core Erlang → BEAM
With a variety of translators along the way too.
Basically take this Elixir:
defmodule :tester do
def hi, do: "there"
end
To this Elixir AST:
{:defmodule, [context: Elixir, import: Kernel],
[:tester,
[do: {:def, [context: Elixir, import: Kernel],
[{:hi, [context: Elixir], Elixir}, [do: "there"]]}]]}
To this Erlang:
-module(tester).
-export([hi/0]).
hi() -> <<"there">>.
To this Core Erlang:
module 'tester' ['hi'/0,
'module_info'/0,
'module_info'/1]
attributes []
'hi'/0 =
%% Line 3
fun () ->
#{#<116>(8,1,'integer',['unsigned'|['big']]),
#<104>(8,1,'integer',['unsigned'|['big']]),
#<101>(8,1,'integer',['unsigned'|['big']]),
#<114>(8,1,'integer',['unsigned'|['big']]),
#<101>(8,1,'integer',['unsigned'|['big']])}#
'module_info'/0 =
fun () ->
call 'erlang':'get_module_info'
('tester')
'module_info'/1 =
fun (_cor0) ->
call 'erlang':'get_module_info'
('tester', _cor0)
To this BEAM Assembly:
00007F031584F908: i_func_info_IaaI 0 tester hi 0
00007F031584F930: move_return_c <<"there">>
00007F031584F940: i_func_info_IaaI 0 tester module_info 0
00007F031584F968: move_cr tester r(0)
00007F031584F978: allocate_tt 0 1
00007F031584F988: call_bif_e erlang:get_module_info/1
00007F031584F998: deallocate_return_Q 0
00007F031584F9A8: i_func_info_IaaI 0 tester module_info 1
00007F031584F9D0: move_rx r(0) x(1)
00007F031584F9E0: move_cr tester r(0)
00007F031584F9F0: allocate_tt 0 2
00007F031584FA00: call_bif_e erlang:get_module_info/2
00007F031584FA10: deallocate_return_Q 0
And that is what is loaded by the VM.