plymio_ast v0.2.0 Plymio.Ast.Signature

Utility Functions for Creating Quoted Function Signatures (a list of Asts).

The Signature DSL

signature_create/2 implements a trivially simple dsl for creating unquotable signatures.

It always returns a list of unquotable values (asts) expected to be used with Kernel.SpecialForms.unquote_splicing/1.

The signature passed to signature_create/2 must be one or more signature items.

Each signature item results in one unquotable argument and can have one of a number of forms:

Signature Item - item (Atom)

When the item is an atom, and the item is a key in the unquotables (see the signature options), the value is returned, else the argument will be the the result of Macro.var(item, nil).

iex> :arg0 |> helper_signature_create_to_string
"(arg0)"

iex> [:arg0, :arg1, :arg2] |> helper_signature_create_to_string
"(arg0, arg1, arg2)"

iex> unquotables = %{arg1: Macro.var(:arg111, nil), arg3: Macro.var(:arg3, nil)}
...> [:arg0, :arg1, :arg2]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg0, arg111, arg2)"

Signature Item - ast (3tuple)

If the item is already a valid ast, it will be used directly.

iex> Macro.var(:arg42, nil) |> helper_signature_create_to_string
"(arg42)"

iex> unquotables = %{arg1: Macro.var(:arg111, nil), arg3: Macro.var(:arg3, nil)}
...> [Macro.var(:arg42, nil), :arg1, :arg2]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg42, arg111, arg2)"

Signature Item - {value, default}

When the item is a 2tuple, the first element is resolved as before.

The second element is taken as the default value and is broadly resolved in the same way as the first element:

When the default is an atom it is first looked up in the :unquotables (if supplied) or escaped (if necessary).

iex> {:arg0, 42} |> helper_signature_create_to_string
"(arg0 \\\\ 42)"

iex> {:arg0, :arg0_default} |> helper_signature_create_to_string
"(arg0 \\\\ :arg0_default)"

iex> {:arg0, %{a: 1}} |> helper_signature_create_to_string
"(arg0 \\\\ %{a: 1})"

iex> unquotables = %{
...>   arg1: Macro.var(:arg111, nil), arg3: Macro.var(:arg3, nil),
...>   default_x1: :x1, default_y2: %{a: 1}, default_z3: {1, :two, "tre"}}
...> [{:arg0, :default_z3}, :arg1, {:arg2, :default_x1}]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg0 \\\\ {1, :two, \"tre\"}, arg111, arg2 \\\\ :x1)"

When the default is already an ast it is used directly:

iex> default_ast = %{a: 1} |> Macro.escape
...> {:arg0, default_ast} |> helper_signature_create_to_string
"(arg0 \\\\ %{a: 1})"

There are a few special (Atom) defaults for convenience

iex> {:arg0, :empty_map} |> helper_signature_create_to_string
"(arg0 \\\\ %{})"

iex> {:arg0, :empty_list} |> helper_signature_create_to_string
"(arg0 \\\\ [])"

iex> {:arg0, :empty_tuple} |> helper_signature_create_to_string
"(arg0 \\\\ {})"

true, false and nil work as expected

iex> {:arg0, nil} |> helper_signature_create_to_string
"(arg0 \\\\ nil)"

iex> {:arg0, true} |> helper_signature_create_to_string
"(arg0 \\\\ true)"

iex> {:arg0, false} |> helper_signature_create_to_string
"(arg0 \\\\ false)"

The Signature Options

The options that can be given to signature_create/2 are:

Signature Options - :unquotables

If given, the :unquotables option must be a map where the keys are atoms and the values an ast.

The map is used as a dictionary to look up signature item that are atoms.

Note, for convenience, any non valid ast values are escaped (Macro.escape/1)

Summary

Functions

See above for the explanation of the arguments to signature_create/2 and more examples

Types

signature()
signature() :: signature_item | [signature_item]
signature_ast()
signature_ast() :: [unquotable]
signature_default()
signature_default ::
  nil |
  false |
  true |
  :empty_map |
  :empty_list |
  :empty_tuple |
  unquotables_map_key |
  unquotable
signature_entity()
signature_entity() :: unquotable | unquotables_map_key
signature_option()
signature_option() :: {:unquotables, unquotables_map}
signature_options()
signature_options() :: [signature_option]
unquotable()
unquotable() :: Macro.t
unquotables_map()
unquotables_map() :: %{optional(unquotables_map_key) => unquotables_map_value}
unquotables_map_key()
unquotables_map_key() :: atom
unquotables_map_value()
unquotables_map_value() :: unquotable

Functions

signature_create(signature, opts \\ [])
signature_create(signature, signature_options) :: signature_ast

See above for the explanation of the arguments to signature_create/2 and more examples.

The example below repeat some of the above but show both the returned signature ast list and then the result of calling Macro.to_string/1.

Note signature_create/2 ensures the the returned signature is a valid ast, its does not attempt to validate its syntax: that is left to the compiler.

Examples

In these examples, an explicit default (e.g. arg0 \\ 42) for the argument is provided:

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, 42}
...> |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg1, [], nil}, 42]}]

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, 42}
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg1 \\\\ 42)"

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> [:arg0, {:arg1, nil}]
...> |> helper_signature_create(unquotables: unquotables)
[{:arg0, [], nil}, {:\\, [], [{:arg1, [], nil}, nil]}]

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> [:arg0, {:arg1, nil}]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg0, arg1 \\\\ nil)"

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> [{:arg0, %{a: 1}}, {:arg1, true}]
...> |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg0, [], nil}, {:%{}, [], [a: 1]}]}, {:\\, [], [{:arg1, [], nil}, true]}]

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> [{:arg0, %{a: 1}}, {:arg1, true}]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg0 \\\\ %{a: 1}, arg1 \\\\ true)"

In these examples, the default is a key in the quotables map

iex> unquotables = %{arg1: Macro.var(:arg1, nil), default: 42}
...> {:arg1, :default}
...> |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg1, [], nil}, 42]}]

iex> unquotables = %{arg1: Macro.var(:arg1, nil), default: 42}
...> {:arg1, :default}
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg1 \\\\ 42)"

iex> unquotables = %{
...>   arg1: Macro.var(:arg1, nil),
...>   def42: 42,
...>   defmap1: Macro.escape(%{x: 99})}
...> [{Macro.var(:arg2, nil), :def42}, {:arg1, :defmap1}]
...> |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg2, [], nil}, 42]}, {:\\, [], [{:arg1, [], nil}, {:%{}, [], [x: 99]}]}]

iex> unquotables = %{
...>   arg1: Macro.var(:arg1, nil),
...>   def42: 42,
...>   defmap1: Macro.escape(%{x: 99})}
...> [{Macro.var(:arg2, nil), :def42}, {:arg1, :defmap1}]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg2 \\\\ 42, arg1 \\\\ %{x: 99})"

In these examples, a pre-existing ast is supplied

iex> Macro.var(:arg2, nil) |> helper_signature_create
 [{:arg2, [], nil}]

 iex> {Macro.var(:arg2, nil), 42} |> helper_signature_create
 [{:\\, [], [{:arg2, [], nil}, 42]}]

In these examples, a range of signature values are used

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil), def42: 42}
...> [{:arg0, %{a: 1}}, :arg1, {Macro.var(:arg2, nil), :def42}]
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg0 \\\\ %{a: 1}, arg1, arg2 \\\\ 42)"

In these examples some of the “convenience” values for the signature are used for defaults

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, :empty_list} |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg1, [], nil}, []]}]

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, :empty_list} |> helper_signature_create_to_string(unquotables: unquotables)
"(arg1 \\\\ [])"

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, :empty_map}
...> |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg1, [], nil}, {:%{}, [], []}]}]

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, :empty_map}
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg1 \\\\ %{})"

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, :empty_tuple}
...> |> helper_signature_create(unquotables: unquotables)
[{:\\, [], [{:arg1, [], nil}, {:{}, [], []}]}]

iex> unquotables = %{arg0: Macro.var(:arg0, nil), arg1: Macro.var(:arg1, nil)}
...> {:arg1, :empty_tuple}
...> |> helper_signature_create_to_string(unquotables: unquotables)
"(arg1 \\\\ {})"