defmodule Igniter.Code.Tuple do @moduledoc """ Utilities for working with tuples. """ alias Igniter.Code.Common alias Sourceror.Zipper @doc "Returns `true` if the zipper is at a literal tuple, `false` if not." @spec tuple?(Zipper.t()) :: boolean() def tuple?(item) do item = Igniter.Code.Common.maybe_move_to_single_child_block(item) case item.node do {:{}, _, _} -> true {_, _} -> true _ -> false end end @doc "Appends `quoted` to the elem" @spec append_elem(Zipper.t(), quoted :: Macro.t()) :: {:ok, Zipper.t()} | :error def append_elem(zipper, quoted) do if tuple?(zipper) do zipper = Igniter.Code.Common.maybe_move_to_single_child_block(zipper) case zipper.node do {l, r} -> {:ok, Zipper.replace(zipper, {:{}, [], [l, r, quoted]})} {:{}, _, list} -> {:ok, Zipper.replace(zipper, {:{}, [], list ++ [quoted]})} end else :error end end @spec elem_equals?(Zipper.t(), elem :: non_neg_integer(), value :: term) :: boolean() def elem_equals?(zipper, elem, value) do case tuple_elem(zipper, elem) do {:ok, zipper} -> Igniter.Code.Common.nodes_equal?(zipper, value) _ -> false end end @doc "Returns a zipper at the tuple element at the given index, or `:error` if the index is out of bounds." @spec tuple_elem(Zipper.t(), elem :: non_neg_integer()) :: {:ok, Zipper.t()} | :error def tuple_elem(item, elem) do item |> Common.maybe_move_to_single_child_block() |> Zipper.down() |> Common.move_right(elem) |> case do {:ok, nth} -> {:ok, Common.maybe_move_to_single_child_block(nth)} :error -> :error end end end