defmodule Mix.Tasks.Firebird.Target.Inspect do @moduledoc """ Inspect the compilation pipeline for a specific source file. Shows the output of each pipeline stage, useful for debugging compilation issues. ## Usage # Inspect all stages for a file mix firebird.target.inspect lib/math.ex # Inspect a specific stage mix firebird.target.inspect lib/math.ex --stage ir mix firebird.target.inspect lib/math.ex --stage wat mix firebird.target.inspect lib/math.ex --stage type_infer # Run with optimizations mix firebird.target.inspect lib/math.ex --optimize --tco ## Stages - `parse` - Elixir AST - `ir` - Firebird IR - `optimize` - Optimized IR - `type_infer` - Typed IR - `validate` - Validation result - `wat` - WebAssembly Text Format - `wasm` - WASM binary info """ use Mix.Task @shortdoc "Inspect WASM compilation pipeline stages" @switches [ stage: :string, optimize: :boolean, tco: :boolean, inline: :boolean ] @aliases [ s: :stage ] @impl Mix.Task def run(args) do {opts, paths, _} = OptionParser.parse(args, switches: @switches, aliases: @aliases) if Enum.empty?(paths) do Mix.raise("Usage: mix firebird.target.inspect [--stage ]") end file = hd(paths) unless File.regular?(file) do Mix.raise("File not found: #{file}") end source = File.read!(file) stage = Keyword.get(opts, :stage) pipeline_opts = Keyword.take(opts, [:optimize, :tco, :inline]) Mix.shell().info("🔍 Firebird Pipeline Inspector") Mix.shell().info(" File: #{file}") Mix.shell().info("") if stage do stage_atom = String.to_atom(stage) output = Firebird.Target.Pipeline.inspect_stage(stage_atom, source, pipeline_opts) Mix.shell().info(output) else # Show all stages case Firebird.Target.Pipeline.run_all(source, pipeline_opts) do {:ok, results} -> Mix.shell().info(" ✅ Parse: AST generated") Mix.shell().info( " ✅ IR: #{results.ir.name} (#{length(results.ir.functions)} functions)" ) Mix.shell().info(" ✅ Validated") Enum.each(results.typed_ir.functions, fn f -> params = if f.type, do: Enum.map(f.type.params, &to_string/1) |> Enum.join(", "), else: "?" ret = if f.type, do: to_string(f.type.return), else: "?" Mix.shell().info(" #{f.name}(#{params}) -> #{ret}") end) Mix.shell().info(" ✅ WAT: #{byte_size(results.wat)} bytes") Mix.shell().info(" ✅ WASM: #{byte_size(results.wasm)} bytes") {:error, reason} -> Mix.shell().error(" ❌ Pipeline failed: #{inspect(reason)}") end end :ok end end