lib/zig/analyzer.ex

defmodule Zig.Analyzer do
  @moduledoc false
  # tools to analyze AST generated by Zig.Parser

  def info_for(parser_output, symbol) do
    # TODO: cache info_for results.
    path = String.split(symbol, ".")
    find(parser_output.code, path)
  end

  def find(ast, [head | rest]) do
    Enum.find(ast, fn
      {:const, _, {name, _, _}} ->
        name_str = Atom.to_string(name)

        case {head == name_str, rest} do
          {true, []} ->
            true

          {true, _} ->
            find(ast, rest)

          _ ->
            nil
        end

      {:fn, _, parts} when rest == [] ->
        if name = parts[:name] do
          Atom.to_string(name) == head
        end

      _ ->
        nil
    end)
  end

  def translate_location(parsed, file, line) do
    location_search(parsed.comments, line, nil) || {file, line}
  end

  defp location_search([{_, %{line: this_line}} | _], line, last)
       when this_line > line,
       do: last

  defp location_search([{" ref " <> ref, %{line: this_line}} | rest], line, _) do
    [file, lineoffset] = String.split(ref, ":")
    target_line = line - this_line + String.to_integer(lineoffset)
    location_search(rest, line, {file, target_line})
  end

  defp location_search([_ | rest], line, last), do: location_search(rest, line, last)

  defp location_search([], _, last), do: last
end