Packages
metastatic
0.2.0
0.26.0
0.25.0
0.24.1
0.24.0
0.23.0
0.22.2
0.22.1
0.22.0
0.21.3
0.21.2
0.21.1
0.21.0
0.20.3
0.20.2
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.1
0.15.0
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.0
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.2
0.9.1
0.9.0
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.1
0.7.0
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.0
0.1.3
0.1.2
0.1.1
0.1.0
Cross-language code meta-model library using unified MetaAST representation. Parse, transform, and translate code across Python, Elixir, Ruby, Erlang, Haskell, and more via a shared three-tuple AST format.
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/metastatic.control_flow.ex
defmodule Mix.Tasks.Metastatic.ControlFlow do
@shortdoc "Generates control flow graph"
use Mix.Task
alias Metastatic.Analysis.ControlFlow
alias Metastatic.Builder
def run(args) do
{opts, files, _} =
OptionParser.parse(args, strict: [format: :string, language: :string, output: :string])
case files do
[] ->
Mix.shell().error("Usage: mix metastatic.control_flow FILE [--format dot|d3|json]")
exit({:shutdown, 2})
[file | _] ->
analyze(file, opts)
end
end
defp analyze(file, opts) do
unless File.exists?(file),
do:
(
Mix.shell().error("File not found")
exit({:shutdown, 2})
)
source = File.read!(file)
lang = opts[:language] || detect_lang(file)
format = opts[:format] || "json"
case Builder.from_source(source, String.to_atom(lang)) do
{:ok, doc} ->
{:ok, result} = ControlFlow.analyze(doc)
output =
case format do
"dot" -> ControlFlow.Result.to_dot(result)
"d3" -> Jason.encode!(ControlFlow.Result.to_d3_json(result), pretty: true)
_ -> Jason.encode!(ControlFlow.Result.to_map(result), pretty: true)
end
if opts[:output] do
File.write!(opts[:output], output)
Mix.shell().info("CFG written to #{opts[:output]}")
else
Mix.shell().info(output)
end
exit({:shutdown, 0})
{:error, reason} ->
Mix.shell().error("Parse error: #{inspect(reason)}")
exit({:shutdown, 2})
end
end
defp detect_lang(file) do
case Path.extname(file) do
".py" ->
"python"
".ex" ->
"elixir"
".exs" ->
"elixir"
".erl" ->
"erlang"
".rb" ->
"ruby"
".hs" ->
"haskell"
_ ->
Mix.shell().error("Cannot detect language")
exit({:shutdown, 2})
end
end
end