Capstone.Vendor.Sourceror.Code.Common (Capstone v0.33.3)

Copy Markdown View Source

General purpose utilities for working with Capstone.Vendor.Sourceror.Zipper.

Summary

Functions

Adds the provided code to the zipper.

Returns a list of zippers to each node that satisfies the predicate function, or an empty list if none are found.

Enters a block, and moves to the first child, or returns the zipper unmodified.

Enters a block with a single child, and moves to that child, or returns the zipper unmodified.

Moves a zipper to the left.

Moves nextwards (depth-first), until the provided predicate returns true.

Moves a zipper to the right.

Moves to the first node that matches the predicate.

Matches and moves to the location of a __cursor__ in provided source code.

Moves to the cursor that matches the provided pattern or one of the provided patterns, in the current scope.

Moves to a do block for the current call.

Moves to the last node that matches the predicate.

Moves to the next node that matches the given pattern.

Moves to the next zipper that matches the predicate.

Moves a zipper upwards.

Moves to the last node before the node that matches the predicate, going upwards.

Returns true if the current node matches the given pattern.

Checks if two nodes are equal.

Removes any nodes matching the provided pattern, until there are no matches left.

Removes all nodes matching the given predicate with the given function.

Replaces code with new code.

Moves the zipper all the way to the right, potentially entering a single value block.

Updates all nodes matching the given predicate with the given function.

Returns true if the node represents a variable assignment.

Runs the function fun on the subtree of the currently focused node and returns the updated zipper.

Functions

add_code(zipper, new_code, opts \\ [])

Adds the provided code to the zipper.

Options

  • :placement - :after | :before. Determines if the code goes :after or :before the current node. Defaults to :after.

add_comment(zipper, comment, opts \\ [])

extendable_block?(arg1)

find_all(zipper, predicate)

Returns a list of zippers to each node that satisfies the predicate function, or an empty list if none are found.

The optional second parameters specifies the direction, defaults to :next.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> zippers = Capstone.Vendor.Sourceror.Code.Common.find_all(zipper, fn z -> match?({:__block__, _, [_]}, z.node) end)
iex> length(zippers) >= 3
true

See also move_to/2.

maybe_move_to_block(zipper)

Enters a block, and moves to the first child, or returns the zipper unmodified.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("(1 + 2)") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> zipper = Capstone.Vendor.Sourceror.Code.Common.maybe_move_to_block(zipper)
iex> match?({:+, _, _}, zipper.node)
true

See also maybe_move_to_single_child_block/1.

maybe_move_to_single_child_block(zipper)

@spec maybe_move_to_single_child_block(Capstone.Vendor.Sourceror.Zipper.t()) ::
  Capstone.Vendor.Sourceror.Zipper.t()

Enters a block with a single child, and moves to that child, or returns the zipper unmodified.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("(1)") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> zipper = Capstone.Vendor.Sourceror.Code.Common.maybe_move_to_single_child_block(zipper)
iex> match?({:__block__, _, [1]}, zipper.node)
true

See also maybe_move_to_block/1.

move_left(zipper, pred_or_n)

Moves a zipper to the left.

If the second argument is a predicate function, it will be called on the zipper and then move leftwards until the predicate returns true. This function will automatically enter and exit blocks.

If the second argument is a non-negative integer, it will move left that many times if possible, returning :error otherwise.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.move_to(zipper, fn z -> match?({:__block__, _, [3]}, z.node) end)
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.move_left(zipper, 1)
iex> match?({:__block__, _, [2]}, zipper.node)
true

See also move_right/2.

move_next(zipper, pred)

Moves nextwards (depth-first), until the provided predicate returns true.

Returns :error if the end is reached without finding a match.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, result} = Capstone.Vendor.Sourceror.Code.Common.move_next(zipper, fn z -> match?({:__block__, _, [2]}, z.node) end)
iex> match?({:__block__, _, [2]}, result.node)
true

See also move_to/2.

move_right(zipper, pred_or_n)

Moves a zipper to the right.

If the second argument is a predicate function, it will be called on the zipper and then move rightwards until the predicate returns true. This function will automatically enter and exit blocks.

If the second argument is a non-negative integer, it will move right that many times if possible, returning :error otherwise.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.move_to(zipper, fn z -> match?({:__block__, _, [1]}, z.node) end)
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.move_right(zipper, 1)
iex> match?({:__block__, _, [2]}, zipper.node)
true

See also move_left/2.

move_to(zipper, pred)

Moves to the first node that matches the predicate.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("foo = 1") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, result} = Capstone.Vendor.Sourceror.Code.Common.move_to(zipper, fn z -> match?({:=, _, _}, z.node) end)
iex> match?({:=, _, _}, result.node)
true

See also move_to_last/2.

move_to_cursor(zipper, pattern)

Matches and moves to the location of a __cursor__ in provided source code.

Use __cursor__() to match a cursor in the provided source code. Use __ to skip any code at a point.

For example:

zipper =
  """
  if true do
    10
  end
  """
  |> Capstone.Vendor.Sourceror.Zipper.zip()

pattern =
  """
  if __ do
    __cursor__()
  end
  """

zipper
|> Capstone.Vendor.Sourceror.Code.Common.move_to_cursor(pattern)
|> Zipper.node()
# => 10

move_to_cursor_match_in_scope(zipper, patterns)

@spec move_to_cursor_match_in_scope(
  Capstone.Vendor.Sourceror.Zipper.t(),
  String.t() | [String.t()]
) ::
  {:ok, Capstone.Vendor.Sourceror.Zipper.t()} | :error

Moves to the cursor that matches the provided pattern or one of the provided patterns, in the current scope.

See move_to_cursor/2 for an example of a pattern.

move_to_do_block(zipper)

@spec move_to_do_block(Capstone.Vendor.Sourceror.Zipper.t()) ::
  {:ok, Capstone.Vendor.Sourceror.Zipper.t()} | :error

Moves to a do block for the current call.

For example, at a node like:

foo do
  10
end

You would get a zipper back at 10.

See also move_upwards/2.

move_to_last(zipper, pred)

Moves to the last node that matches the predicate.

Similar to move_to/2 but it doesn't stop at the first match, for example a zipper for the following code:

port = 4000
port = 4001

With a match for port = _ as {:=, _, [{:port, _, _}, _]}, will return the second port variable.

move_to_pattern(zipper, pattern)

(macro)

Moves to the next node that matches the given pattern.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, result} = Capstone.Vendor.Sourceror.Code.Common.move_to_pattern(zipper, {:__block__, _, [2]})
iex> match?({:__block__, _, [2]}, result.node)
true

See also node_matches_pattern?/2.

move_to_zipper(zipper, pred)

Moves to the next zipper that matches the predicate.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("foo = 1") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, result} = Capstone.Vendor.Sourceror.Code.Common.move_to_zipper(zipper, fn z -> match?({:=, _, _}, z.node) end)
iex> match?({:=, _, _}, result.node)
true

See also move_to/2.

move_upwards(zipper, pred_or_n)

Moves a zipper upwards.

If the second argument is a predicate function, it will be called on the zipper and then move upwards until the predicate returns true.

If the second argument is a non-negative integer, it will move upwards that many times if possible, returning :error otherwise.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("defmodule Foo do\ndef bar do\n1\nend\nend") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Function.move_to_def(zipper, :bar, 0)
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.move_upwards(zipper, &match?({:defmodule, _, _}, &1.node))
iex> match?({:defmodule, _, _}, zipper.node)
true

See also move_upwards_until/2.

move_upwards_until(zipper, pred)

Moves to the last node before the node that matches the predicate, going upwards.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("defmodule Foo do\ndef bar do\n1\nend\nend") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Function.move_to_def(zipper, :bar, 0)
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.move_upwards_until(zipper, &match?({:defmodule, _, _}, &1.node))
iex> match?({:defmodule, _, _}, zipper.node)
true

See also move_upwards/2.

node_matches_pattern?(zipper, pattern)

(macro)

Returns true if the current node matches the given pattern.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> Capstone.Vendor.Sourceror.Code.Common.node_matches_pattern?(zipper, value when is_list(value))
true

See also move_to_pattern/2.

nodes_equal?(left, right)

@spec nodes_equal?(Capstone.Vendor.Sourceror.Zipper.t() | Macro.t(), Macro.t()) ::
  boolean()

Checks if two nodes are equal.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("foo = 1") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> node = Capstone.Vendor.Sourceror.Zipper.node(zipper)
iex> Capstone.Vendor.Sourceror.Code.Common.nodes_equal?(zipper, node)
true

parse_to_zipper!(string)

remove(zipper, pred)

Removes any nodes matching the provided pattern, until there are no matches left.

See also remove_all_matches/2.

remove_all_matches(zipper, pred)

Removes all nodes matching the given predicate with the given function.

Recurses until the predicate no longer returns false.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> zipper = Capstone.Vendor.Sourceror.Code.Common.remove_all_matches(zipper, 
...>   fn z -> match?({:__block__, _, [2]}, z.node) end)
iex> Capstone.Vendor.Sourceror.to_string(zipper.node)
"[1, 3]"

See also update_all_matches/3.

replace_code(zipper, code)

Replaces code with new code.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("foo = 1") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> zipper = Capstone.Vendor.Sourceror.Code.Common.move_to_zipper(zipper, fn z -> match?({:=, _, _}, z.node) end) |> elem(1)
iex> zipper = Capstone.Vendor.Sourceror.Code.Common.replace_code(zipper, "bar = 2")
iex> Capstone.Vendor.Sourceror.to_string(zipper.node)
"bar = 2"

See also add_code/3.

rightmost(zipper)

Moves the zipper all the way to the right, potentially entering a single value block.

single_child_block?(zipper)

@spec single_child_block?(Capstone.Vendor.Sourceror.Zipper.t()) :: boolean()

update_all_matches(zipper, pred, fun)

@spec update_all_matches(
  Capstone.Vendor.Sourceror.Zipper.t(),
  (Capstone.Vendor.Sourceror.Zipper.t() -> boolean()),
  (Capstone.Vendor.Sourceror.Zipper.t() ->
     {:ok, Capstone.Vendor.Sourceror.Zipper.t() | {:code, term()}}
     | {:warning | :error, term()})
) :: {:ok, Capstone.Vendor.Sourceror.Zipper.t()} | {:warning | :error, term()}

Updates all nodes matching the given predicate with the given function.

Recurses until the predicate no longer returns false.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("foo = 1") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.update_all_matches(zipper, 
...>   fn z -> match?({:=, _, _}, z.node) end,
...>   fn z -> {:ok, Capstone.Vendor.Sourceror.Code.Common.replace_code(z, "bar = 2")} end)
iex> Capstone.Vendor.Sourceror.to_string(zipper.node) |> String.contains?("bar = 2")
true

See also remove_all_matches/2.

variable_assignment?(arg1, name)

@spec variable_assignment?(
  zipper :: Capstone.Vendor.Sourceror.Zipper.t(),
  name :: atom()
) :: boolean()

Returns true if the node represents a variable assignment.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("foo = 1") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> Capstone.Vendor.Sourceror.Code.Common.variable_assignment?(zipper, :foo)
true
iex> Capstone.Vendor.Sourceror.Code.Common.variable_assignment?(zipper, :bar)
false

within(top_zipper, fun)

Runs the function fun on the subtree of the currently focused node and returns the updated zipper.

fun must return {:ok, zipper} or :error, which may be positioned at the top of the subtree.

Examples

iex> zipper = Capstone.Vendor.Sourceror.parse_string!("[1, 2, 3]") |> Capstone.Vendor.Sourceror.Zipper.zip()
iex> {:ok, zipper} = Capstone.Vendor.Sourceror.Code.Common.within(zipper, fn z -> 
...>   {:ok, Capstone.Vendor.Sourceror.Code.Common.replace_code(z, "[4, 5, 6]")}
...> end)
iex> Capstone.Vendor.Sourceror.to_string(zipper.node)
"[4, 5, 6]"