Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us
Notesclub

Kernel.Utils

elixir_livebooks/kernel_utils.livemd

Kernel.Utils

Function announce_struct/1

Announcing callback for defstruct.

Function defdelegate/2

Callback for defdelegate.

Function defstruct/2

Callback for defstruct.

Function destructure/2

Callback for destructure.

Function raise/1

Callback for raise.

Macro defguard/2

Callback for defguard.

Rewrites an expression so it can be used both inside and outside a guard.

Take, for example, the expression:

is_integer(value) and rem(value, 2) == 0

If we wanted to create a macro, is_even, from this expression, that could be used in guards, we’d have to take several things into account.

First, if this expression is being used inside a guard, value needs to be unquoted each place it occurs, since it has not yet been at that point in our macro.

Secondly, if the expression is being used outside of a guard, we want to unquote value, but only once, and then re-use the unquoted form throughout the expression.

This helper does exactly that: takes the AST for an expression and a list of variable references it should be aware of, and rewrites it into a new expression that checks for its presence in a guard, then unquotes the variable references as appropriate.

The following code

expression = quote do: is_integer(value) and rem(value, 2) == 0
variable_references = [value: Elixir]
Kernel.Utils.defguard(expression, variable_references) |> Macro.to_string() |> IO.puts()

would print a code similar to:

case Macro.Env.in_guard?(__CALLER__) do
  true ->
    quote do
      is_integer(unquote(value)) and rem(unquote(value), 2) == 0
    end

  false ->
    quote do
      value = unquote(value)
      is_integer(value) and rem(value, 2) == 0
    end
end