Packages
metastatic
0.13.2
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"
@moduledoc """
Generates a control flow graph (CFG) for a given source file.
## Usage
mix metastatic.control_flow FILE [options]
## Options
* `--format` - Output format: json (default), dot, or d3
* `--language` - Source language: python, elixir, erlang, ruby, or haskell (auto-detected if not specified)
* `--output` - Write output to file instead of stdout
## Examples
# Generate CFG in DOT format (for Graphviz)
mix metastatic.control_flow my_file.py --format dot
# Generate D3.js JSON for interactive visualization
mix metastatic.control_flow my_file.ex --format d3 --output cfg.json
# JSON output (default)
mix metastatic.control_flow my_file.rb
## Output Formats
* `json` - Full CFG as JSON map (default)
* `dot` - DOT format for Graphviz rendering
* `d3` - D3.js JSON for web visualization
## Exit Codes
* 0 - Success
* 2 - Error during analysis
"""
use Mix.Task
@dialyzer {:no_return, run: 1}
alias Metastatic.Analysis.ControlFlow
alias Metastatic.Builder
@impl Mix.Task
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