Packages
sourceror
1.11.0
1.12.2
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.2
1.8.0
1.7.1
1.7.0
1.6.0
1.5.0
1.4.0
1.3.0
1.2.1
1.2.0
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.1
0.6.0
0.5.0
0.4.0
0.3.0
0.2.2
Utilities to work with Elixir source code.
Current section
Files
Jump to
Current section
Files
lib/sourceror/code/tuple.ex
# Copyright 2024 Zach Daniel. All rights reserved.
# This file is licensed to you under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software distributed under
# the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
# OF ANY KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
# Branched from https://github.com/ash-project/igniter
# Initial implementation Copyright (c) 2024 Zach Daniel, licenced under Apache 2.0
defmodule Sourceror.Code.Tuple do
@moduledoc """
Utilities for working with tuples.
"""
alias Sourceror.Code.Common
alias Sourceror.Zipper
@doc """
Returns `true` if the zipper is at a literal tuple, `false` if not.
## Examples
iex> zipper = Sourceror.parse_string!("{1, 2, 3}") |> Sourceror.Zipper.zip()
iex> Sourceror.Code.Tuple.tuple?(zipper)
true
iex> zipper = Sourceror.parse_string!("[1, 2, 3]") |> Sourceror.Zipper.zip()
iex> Sourceror.Code.Tuple.tuple?(zipper)
false
See also `tuple_elem/2`.
"""
@spec tuple?(Zipper.t()) :: boolean()
def tuple?(item) do
item = Sourceror.Code.Common.maybe_move_to_single_child_block(item)
case item.node do
{:{}, _, _} -> true
{_, _} -> true
_ -> false
end
end
@doc """
Appends `quoted` to the tuple.
## Examples
iex> zipper = Sourceror.parse_string!("{1, 2}") |> Sourceror.Zipper.zip()
iex> {:ok, zipper} = Sourceror.Code.Tuple.append_elem(zipper, 3)
iex> Sourceror.to_string(zipper.node)
"{1, 2, 3}"
See also `tuple_elem/2`.
"""
@spec append_elem(Zipper.t(), quoted :: Macro.t()) :: {:ok, Zipper.t()} | :error
def append_elem(zipper, quoted) do
if tuple?(zipper) do
zipper = Sourceror.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
@doc """
Returns true if the element at the given index equals the given value.
## Examples
iex> zipper = Sourceror.parse_string!("{1, 2, 3}") |> Sourceror.Zipper.zip()
iex> Sourceror.Code.Tuple.elem_equals?(zipper, 0, 1)
true
iex> Sourceror.Code.Tuple.elem_equals?(zipper, 0, 2)
false
See also `tuple_elem/2`.
"""
@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} ->
Sourceror.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.
## Examples
iex> zipper = Sourceror.parse_string!("{1, 2, 3}") |> Sourceror.Zipper.zip()
iex> {:ok, result} = Sourceror.Code.Tuple.tuple_elem(zipper, 1)
iex> match?({:__block__, _, [2]}, result.node)
true
See also `tuple?/1`.
"""
@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