Current section
Files
Jump to
Current section
Files
lib/mix/tasks/beam.file.ex
defmodule Mix.Tasks.Beam.File do
@shortdoc "Prints the decompiled source for a module."
@moduledoc """
#{@shortdoc}
```shell
mix beam.file module switch
```
The argument `module` specifies the `module` to decompile. The `switch` can be
one of `--elixir`, `--erlang`, or `--byte-code`.
Decompiling with `--elixir` returns the expanded Elixir code.
"""
use Mix.Task
@opts strict: [elixir: :boolean, erlang: :boolean, byte_code: :boolean]
@error ~s|Could not invoke task "beam.file":|
@impl Mix.Task
def run(opts) do
opts
|> OptionParser.parse!(@opts)
|> validate()
|> output()
end
defp output({[{type, true}], [module]}) do
Mix.Task.run("compile")
module = Module.concat([module])
module
|> code(type)
|> check()
|> IO.puts()
end
defp check({:ok, code}), do: code
defp check({:error, error}) do
Mix.raise("BeamFileError: #{to_string(error)}")
end
defp code(module, :elixir), do: BeamFile.elixir_code(module)
defp code(module, :erlang), do: BeamFile.erl_code(module)
defp code(module, :byte_code) do
with {:ok, byte_code} <- BeamFile.byte_code(module) do
{:ok, inspect(byte_code, pretty: true, limit: :infinity)}
end
end
defp validate({[], _args}) do
Mix.raise("""
#{@error}
Missing one of the switches `--elixir`, `--erlang`, or `--byte-code`.
""")
end
defp validate({_opts, []}) do
Mix.raise("""
#{@error}
Missing a moudle name.
""")
end
defp validate({opts, args}) when length(opts) > 1 or length(args) > 1 do
Mix.raise("""
#{@error}
Too many arguments.
""")
end
defp validate(opts), do: opts
end