defmodule Mix.Tasks.Firebird.Analyze do @moduledoc """ Analyze Elixir source files for WASM compilability. Shows which functions can be compiled, estimates complexity, and provides optimization suggestions. ## Usage mix firebird.analyze lib/wasm_modules/math.ex mix firebird.analyze lib/wasm_modules/ ## Output For each file, shows: - Module name - Function list with compilability status - Recursion analysis (tail-recursive, exponential, etc.) - Optimization suggestions """ use Mix.Task @shortdoc "Analyze Elixir files for WASM compilability" @impl Mix.Task def run(args) do {_opts, paths, _} = OptionParser.parse(args, switches: [], aliases: []) if Enum.empty?(paths) do Mix.raise("No input files specified. Usage: mix firebird.analyze [...]") end files = resolve_files(paths) if Enum.empty?(files) do Mix.raise("No .ex or .exs files found in the specified paths") end Mix.shell().info("🔍 Firebird WASM Analyzer") Mix.shell().info("") Enum.each(files, fn file -> analyze_file(file) end) end defp resolve_files(paths) do Enum.flat_map(paths, fn path -> cond do File.dir?(path) -> Path.wildcard(Path.join(path, "**/*.{ex,exs}")) File.regular?(path) -> [path] true -> [] end end) |> Enum.sort() |> Enum.uniq() end defp analyze_file(path) do Mix.shell().info("📄 #{path}") case Firebird.Compiler.Analyzer.analyze_file(path) do {:ok, analysis} -> print_analysis(analysis) {:error, reason} -> Mix.shell().error(" ❌ Cannot analyze: #{inspect(reason)}") end Mix.shell().info("") end defp print_analysis(analysis) do status = if analysis.compilable, do: "✅ Compilable", else: "⚠ Partial" Mix.shell().info(" Module: #{analysis.module} (#{status})") for func <- analysis.functions do icon = if func.compilable, do: "✅", else: "❌" rec_info = cond do func.tail_recursive -> " [tail-recursive]" func.recursive -> " [recursive]" true -> "" end Mix.shell().info( " #{icon} #{func.name}/#{func.arity} #{func.estimated_complexity}#{rec_info}" ) for issue <- func.issues do Mix.shell().info(" ⚠ #{issue}") end end if Enum.any?(analysis.suggestions) do Mix.shell().info("") Mix.shell().info(" 💡 Suggestions:") for sug <- analysis.suggestions do Mix.shell().info(" • #{sug}") end end end end