plymio_ast v1.0.0 Plymio.Ast.Form View Source

Utility Functions for Manipulating Asts (Quoted Forms)

Many functions return either {:ok, value} or {:error, error} where error with be usually an ArgumentError

Link to this section Summary

Functions

maybe_ast_escape/1 escapes (Macro.escape/1) any value other than a module attribute or an existing ast (i.e. Macro.validate/1 returns :ok)

Takes a maybe quoted value and returns the realised value

Takes a maybe quoted value, realises it and, if a function, returns {:ok, function}. Anything else returns :error

Takes a maybe quoted value, realises it using maybe_ast_realise_function/1, and, if {:ok, function}, returns the function, else raises a BadFunctionError exception

Takes a maybe quoted value, realises it and, if a Map, returns {:ok, map}

Takes a maybe quoted value, realises it using maybe_ast_realise_map/1, and if the result is {:ok, map}, returns the map, else raises a BadMapError exception

Takes a maybe quoted value, realises it and, if a compiled module, returns {:ok, module}

Takes a maybe quoted value, realises it using maybe_ast_realise_module/1, and, if {:ok, module}, returns the module, else raises a ArgumentError exception

Takes a maybe quoted value, realises it and, if a tuple, returns {:ok, tuple}

Takes a maybe quoted value, realises it using maybe_ast_realise_tuple/1, and if the result is {:ok, tuple}, returns the tuple, else raises an ArgumentError exception

Takes a maybe quoted value and returns the realised value as {:ok, value}

Takes a maybe quoted value, realises it and, if a function, returns {:ok, function}

Takes a maybe quoted value, realises it using maybe_form_realise_function/1, and, if {:ok, function}, returns the function, else raises error in {:error, error}

Takes a maybe quoted value, realises it and, if a Map, returns {:ok, map}. Otherwise {:error, error} where error will be a BadMapError

Takes a maybe quoted value, realises it using maybe_form_realise_map/1, and if the result is {:ok, map}, returns the map, else raises error in {:error, error}

Takes a maybe quoted value, realises it and, if a compiled module, returns {:ok, module}

Takes a maybe quoted value, realises it using maybe_form_realise_module/1, and, if {:ok, module}, returns the module, else raises error in {:error, error}

Takes a maybe quoted value, realises it and, if a tuple, returns {:ok, tuple}

Takes a maybe quoted value, realises it using maybe_form_realise_tuple/1, and if the result is {:ok, tuple}, returns the tuple, else raises an ArgumentError exception

Link to this section Types

Link to this type error() View Source
error() :: %ArgumentError{__exception__: term(), message: term()}

Link to this section Functions

Link to this function maybe_ast_escape(value) View Source
maybe_ast_escape(any()) :: Macro.t()

maybe_ast_escape/1 escapes (Macro.escape/1) any value other than a module attribute or an existing ast (i.e. Macro.validate/1 returns :ok)

Examples

iex> 42 |> maybe_ast_escape
42

iex> :two |> maybe_ast_escape
:two

iex> %{a: 1} |> maybe_ast_escape
{:%{}, [], [a: 1]}

iex> %{a: 1} |> Macro.escape |> maybe_ast_escape
{:%{}, [], [a: 1]}

iex> [1, %{b: 2}, {:c, 2, :tre}] |> maybe_ast_escape
[1, {:%{}, [], [b: 2]}, {:{}, [], [:c, 2, :tre]}]

iex> [1, %{b: 2}, {:c, 2, :tre}] |> Macro.escape |> maybe_ast_escape
[1, {:%{}, [], [b: 2]}, {:{}, [], [:c, 2, :tre]}]
Link to this function maybe_ast_realise(value) View Source
maybe_ast_realise(any()) :: any()

Takes a maybe quoted value and returns the realised value.

Realisation in this context means extracting the underlying (“unquoted”) value.

Examples

iex> 1 |> maybe_ast_realise
1

iex> :atom |> maybe_ast_realise
:atom

iex> "string" |> maybe_ast_realise
"string"

iex> [1, :atom, "string"] |> maybe_ast_realise
[1, :atom, "string"]

iex> {:x, 42} |> maybe_ast_realise
{:x, 42}

iex> ast = {:x, 42} |> Macro.escape
...> ast |> maybe_ast_realise
{:x, 42}

iex> %{a: 1, b: 2, c: 3} |> maybe_ast_realise
%{a: 1, b: 2, c: 3}

iex> ast = %{a: 1, b: 2, c: 3} |> Macro.escape
...> ast |> maybe_ast_realise
%{a: 1, b: 2, c: 3}

iex> fun = fn x -> x + 5 end
...> fun = fun |> maybe_ast_realise
...> 42 |> fun.()
47

iex> ast = "fn x -> x + 5 end" |> Code.string_to_quoted!
...> fun = ast |> maybe_ast_realise
...> 42 |> fun.()
47

A map’s keys and values are recursively realised:

iex> ast = %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_ast_realise
%{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}

The elements of a tuple are recursively realised:

iex> ast = [{:x, 2, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}] |> Macro.escape
iex> ast |> maybe_ast_realise
[{:x, 2, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}]

The elements of a list are recursively realised:

iex> ast = [{:x,:y,:z}, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}] |> Macro.escape
iex> ast |> maybe_ast_realise
[{:x,:y,:z}, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}]
Link to this function maybe_ast_realise_function(value) View Source
maybe_ast_realise_function(any()) :: {:ok, (... -> any())} | :error

Takes a maybe quoted value, realises it and, if a function, returns {:ok, function}. Anything else returns :error.

iex> fun = fn x -> x end
...> result = fun |> maybe_ast_realise_function
...> match?({:ok, ^fun}, result)
true

iex> quoted_fun = quote(do: fn x -> x end)
...> {:ok, fun} = quoted_fun |> maybe_ast_realise_function
...> is_function(fun, 1)
true

iex> 42 |> maybe_ast_realise_function
:error

iex> {:x, 42} |> Macro.escape
...> |> maybe_ast_realise_function
:error
Link to this function maybe_ast_realise_function!(value) View Source
maybe_ast_realise_function!(any()) :: (... -> any()) | no_return()

Takes a maybe quoted value, realises it using maybe_ast_realise_function/1, and, if {:ok, function}, returns the function, else raises a BadFunctionError exception.

iex> fun = fn x -> x end
...> result = fun |> maybe_ast_realise_function!
...> match?(^fun, result)
true

iex> quoted_fun = quote(do: fn x -> x end)
...> fun = quoted_fun |> maybe_ast_realise_function!
...> is_function(fun, 1)
true

iex> 42 |> maybe_ast_realise_function!
** (BadFunctionError) expected a function, got: :error

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_ast_realise_function!
** (BadFunctionError) expected a function, got: :error
Link to this function maybe_ast_realise_map(value) View Source
maybe_ast_realise_map(any()) :: {:ok, map()} | :error

Takes a maybe quoted value, realises it and, if a Map, returns {:ok, map}.

If the realised value is a Keyword, its is converted to a map and {:ok, map} returned.

Anything else returns :error.

The keys and values are recursively realised.

iex> %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> maybe_ast_realise_map
{:ok, %{a: 1, b: %{b21: 21, b22: 22}, c: 3}}

iex> ast = %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_ast_realise_map
{:ok, %{a: 1, b: %{b21: 21, b22: 22}, c: 3}}

iex> 42 |> maybe_ast_realise_map
:error

iex> ast = {:x, 42} |> Macro.escape
iex> ast |> maybe_ast_realise_map
:error
Link to this function maybe_ast_realise_map!(value) View Source
maybe_ast_realise_map!(any()) :: map() | no_return()

Takes a maybe quoted value, realises it using maybe_ast_realise_map/1, and if the result is {:ok, map}, returns the map, else raises a BadMapError exception.

iex> %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> maybe_ast_realise_map!
%{a: 1, b: %{b21: 21, b22: 22}, c: 3}

iex> ast = %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_ast_realise_map!
%{a: 1, b: %{b21: 21, b22: 22}, c: 3}

iex> 42 |> maybe_ast_realise_map!
** (BadMapError) expected a map, got: :error

iex> ast = {:x, 42} |> Macro.escape
iex> ast |> maybe_ast_realise_map!
** (BadMapError) expected a map, got: :error
Link to this function maybe_ast_realise_module(value) View Source
maybe_ast_realise_module(any()) :: {:ok, atom()} | :error

Takes a maybe quoted value, realises it and, if a compiled module, returns {:ok, module}.

Tests whether the module’s __info__ function works to confirm an actual module.

Anything else returns :error.

iex> mod = (defmodule XYZ1, do: nil) |> elem(1)
...> result = mod |> maybe_ast_realise_module
...> match?({:ok, ^mod}, result)
true

iex> mod = (defmodule XYZ2, do: nil) |> elem(1)
...> quoted_mod = mod |> Macro.escape
...> result = quoted_mod |> maybe_ast_realise_module
...> match?({:ok, ^mod}, result)
true

iex> 42 |> maybe_ast_realise_module
:error

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_ast_realise_module
:error
Link to this function maybe_ast_realise_module!(value) View Source
maybe_ast_realise_module!(any()) :: atom() | no_return()

Takes a maybe quoted value, realises it using maybe_ast_realise_module/1, and, if {:ok, module}, returns the module, else raises a ArgumentError exception.

iex> mod = (defmodule XYZ3, do: nil) |> elem(1)
...> result = mod |> maybe_ast_realise_module!
...> match?(^mod, result)
true

iex> mod = (defmodule XYZ4, do: nil) |> elem(1)
...> quoted_mod = mod |> Macro.escape
...> result = quoted_mod |> maybe_ast_realise_module!
...> match?(^mod, result)
true

iex> :an_atom_but_not_a_module |> maybe_ast_realise_module!
** (ArgumentError) expected a module, got: :error

iex> 42 |> maybe_ast_realise_module!
** (ArgumentError) expected a module, got: :error

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_ast_realise_module!
** (ArgumentError) expected a module, got: :error
Link to this function maybe_ast_realise_tuple(value) View Source
maybe_ast_realise_tuple(any()) :: {:ok, tuple()} | :error

Takes a maybe quoted value, realises it and, if a tuple, returns {:ok, tuple}.

Anything else returns :error.

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3} |> maybe_ast_realise_tuple
{:ok, {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}}

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple
{:ok, {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}}

iex> 42 |> maybe_ast_realise_tuple
:error

iex> %{x: 42}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple
:error
Link to this function maybe_ast_realise_tuple!(value) View Source
maybe_ast_realise_tuple!(any()) :: tuple() | no_return()

Takes a maybe quoted value, realises it using maybe_ast_realise_tuple/1, and if the result is {:ok, tuple}, returns the tuple, else raises an ArgumentError exception.

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3} |> maybe_ast_realise_tuple!
{:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple!
{:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}

iex> 42 |> maybe_ast_realise_tuple!
** (ArgumentError) expected a tuple, got: :error

iex> %{x: 42}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple!
** (ArgumentError) expected a tuple, got: :error
Link to this function maybe_form_realise(value) View Source
maybe_form_realise(any()) :: {:ok, any()} | {:error, error()}

Takes a maybe quoted value and returns the realised value as {:ok, value}.

Otherwise {:error, error} is returned.

Realisation in this context means extracting the underlying (“unquoted”) value.

Examples

iex> 1 |> maybe_form_realise
{:ok, 1}

iex> :atom |> maybe_form_realise
{:ok, :atom}

iex> "string" |> maybe_form_realise
{:ok, "string"}

iex> [1, :atom, "string"] |> maybe_form_realise
{:ok, [1, :atom, "string"]}

iex> {:x, 42} |> maybe_form_realise
{:ok, {:x, 42}}

iex> ast = {:x, 42} |> Macro.escape
...> ast |> maybe_form_realise
{:ok, {:x, 42}}

iex> %{a: 1, b: 2, c: 3} |> maybe_form_realise
{:ok, %{a: 1, b: 2, c: 3}}

iex> ast = %{a: 1, b: 2, c: 3} |> Macro.escape
...> ast |> maybe_form_realise
{:ok, %{a: 1, b: 2, c: 3}}

iex> fun = fn x -> x + 5 end
...> {:ok, fun} = fun |> maybe_form_realise
...> 42 |> fun.()
47

iex> ast = "fn x -> x + 5 end" |> Code.string_to_quoted!
...> {:ok, fun} = ast |> maybe_form_realise
...> 42 |> fun.()
47

A map’s keys and values are recursively realised:

iex> ast = %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_form_realise
{:ok, %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}

The elements of a tuple are recursively realised:

iex> ast = [{:x, 2, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}] |> Macro.escape
iex> ast |> maybe_form_realise
{:ok, [{:x, 2, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}]}

The elements of a list are recursively realised:

iex> ast = [{:x,:y,:z}, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}] |> Macro.escape
iex> ast |> maybe_form_realise
{:ok, [{:x,:y,:z}, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}]}
Link to this function maybe_form_realise_function(value) View Source
maybe_form_realise_function(any()) ::
  {:ok, (... -> any())} |
  {:error, error()} |
  {:error, %BadFunctionError{__exception__: term(), term: term()}}

Takes a maybe quoted value, realises it and, if a function, returns {:ok, function}.

Anything else returns {:error, error} where error is a BadFunctionError.

iex> fun = fn x -> x end
...> result = fun |> maybe_form_realise_function
...> match?({:ok, ^fun}, result)
true

iex> quoted_fun = quote(do: fn x -> x end)
...> {:ok, fun} = quoted_fun |> maybe_form_realise_function
...> is_function(fun, 1)
true

iex> {:error, error} = 42 |> maybe_form_realise_function
...> match?(%BadFunctionError{term: 42}, error)
true

iex> {:error, error} = {:x, 42} |> Macro.escape
...> |> maybe_form_realise_function
...> match?(%BadFunctionError{term: {:x, 42}}, error)
true
Link to this function maybe_form_realise_function!(value) View Source
maybe_form_realise_function!(any()) :: (... -> any()) | no_return()

Takes a maybe quoted value, realises it using maybe_form_realise_function/1, and, if {:ok, function}, returns the function, else raises error in {:error, error}.

iex> fun = fn x -> x end
...> result = fun |> maybe_form_realise_function!
...> match?(^fun, result)
true

iex> quoted_fun = quote(do: fn x -> x end)
...> fun = quoted_fun |> maybe_form_realise_function!
...> is_function(fun, 1)
true

iex> 42 |> maybe_form_realise_function!
** (BadFunctionError) expected a function, got: 42

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_form_realise_function!
** (BadFunctionError) expected a function, got: {:x, 42}
Link to this function maybe_form_realise_map(value) View Source
maybe_form_realise_map(any()) ::
  {:ok, map()} |
  {:error, error()} |
  {:error, %BadMapError{__exception__: term(), term: term()}}

Takes a maybe quoted value, realises it and, if a Map, returns {:ok, map}. Otherwise {:error, error} where error will be a BadMapError.

If the realised value is a Keyword, its is converted to a map and {:ok, map} returned.

The keys and values are recursively realised.

iex> %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> maybe_form_realise_map
{:ok, %{a: 1, b: %{b21: 21, b22: 22}, c: 3}}

iex> ast = %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_form_realise_map
{:ok, %{a: 1, b: %{b21: 21, b22: 22}, c: 3}}

iex> 42 |> maybe_form_realise_map
{:error, %BadMapError{term: 42}}

iex> {:x, 42} |> Macro.escape |> maybe_form_realise_map
{:error, %BadMapError{term: Macro.escape({:x, 42})}}
Link to this function maybe_form_realise_map!(value) View Source
maybe_form_realise_map!(any()) :: map() | no_return()

Takes a maybe quoted value, realises it using maybe_form_realise_map/1, and if the result is {:ok, map}, returns the map, else raises error in {:error, error}.

iex> %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> maybe_form_realise_map!
%{a: 1, b: %{b21: 21, b22: 22}, c: 3}

iex> ast = %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_form_realise_map!
%{a: 1, b: %{b21: 21, b22: 22}, c: 3}

iex> 42 |> maybe_form_realise_map!
** (BadMapError) expected a map, got: 42

iex> ast = {:x, 42} |> Macro.escape
iex> ast |> maybe_form_realise_map!
** (BadMapError) expected a map, got: {:x, 42}
Link to this function maybe_form_realise_module(value) View Source
maybe_form_realise_module(any()) :: {:ok, atom()} | {:error, error()}

Takes a maybe quoted value, realises it and, if a compiled module, returns {:ok, module}.

Tests whether the module’s __info__ function works to confirm an actual module.

Anything else returns {:error, error}.

iex> mod = (defmodule ABC1, do: nil) |> elem(1)
...> result = mod |> maybe_form_realise_module
...> match?({:ok, ^mod}, result)
true

iex> mod = (defmodule ABC2, do: nil) |> elem(1)
...> quoted_mod = mod |> Macro.escape
...> result = quoted_mod |> maybe_form_realise_module
...> match?({:ok, ^mod}, result)
true

iex> {:error, error} = 42 |> maybe_form_realise_module
...> match?(%ArgumentError{message: "expected a module; got: 42"}, error)
true

iex> {:error, error} = {:x, 42}
...> |> Macro.escape
...> |> maybe_form_realise_module
...> match?(%ArgumentError{message: "expected a module; got: {:x, 42}"}, error)
true
Link to this function maybe_form_realise_module!(value) View Source
maybe_form_realise_module!(any()) :: atom() | no_return()

Takes a maybe quoted value, realises it using maybe_form_realise_module/1, and, if {:ok, module}, returns the module, else raises error in {:error, error}.

iex> mod = (defmodule ABC3, do: nil) |> elem(1)
...> result = mod |> maybe_form_realise_module!
...> match?(^mod, result)
true

iex> mod = (defmodule ABC, do: nil) |> elem(1)
...> quoted_mod = mod |> Macro.escape
...> result = quoted_mod |> maybe_form_realise_module!
...> match?(^mod, result)
true

iex> :an_atom_but_not_a_module |> maybe_form_realise_module!
** (ArgumentError) expected a module; got: :an_atom_but_not_a_module

iex> 42 |> maybe_form_realise_module!
** (ArgumentError) expected a module; got: 42

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_form_realise_module!
** (ArgumentError) expected a module; got: {:x, 42}
Link to this function maybe_form_realise_tuple(value) View Source
maybe_form_realise_tuple(any()) :: {:ok, tuple()} | {:error, error()}

Takes a maybe quoted value, realises it and, if a tuple, returns {:ok, tuple}.

Anything else returns {:error, error}.

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3} |> maybe_form_realise_tuple
{:ok, {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}}

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}
...> |> Macro.escape
...> |> maybe_form_realise_tuple
{:ok, {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}}

iex> {:error, error} = 42 |> maybe_form_realise_tuple
...> match?(%ArgumentError{message: "expected a tuple; got: 42"}, error)
true

iex> {:error, error} = %{x: 42}
...> |> Macro.escape
...> |> maybe_form_realise_tuple
...> match?(%ArgumentError{message: "expected a tuple; got: %{x: 42}"}, error)
true
Link to this function maybe_form_realise_tuple!(value) View Source
maybe_form_realise_tuple!(any()) :: tuple() | no_return()

Takes a maybe quoted value, realises it using maybe_form_realise_tuple/1, and if the result is {:ok, tuple}, returns the tuple, else raises an ArgumentError exception.

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3} |> maybe_form_realise_tuple!
{:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}
...> |> Macro.escape
...> |> maybe_form_realise_tuple!
{:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}

iex> 42 |> maybe_form_realise_tuple!
** (ArgumentError) expected a tuple; got: 42

iex> %{x: 42}
...> |> Macro.escape
...> |> maybe_form_realise_tuple!
** (ArgumentError) expected a tuple; got: %{x: 42}