All you need to do is to handle all of the edge cases (in your case special forms), for example:
defmodule Example do
def sample(ast, opts \\ [env: __ENV__])
def sample({:%, _, [aliases, {:%{}, _, keyword}]}, opts) do
aliases |> Macro.expand_literal(opts[:env]) |> struct(keyword)
end
def sample({:%{}, _, keyword}, _opts) do
Map.new(keyword)
end
def sample({:{}, [], list}, _opts) do
List.to_tuple(list)
end
def sample({:<<>>, [], attrs}, _opts) do
Enum.reduce(attrs, <<>>, fn
{:"::", [], [value, size]}, acc -> <<acc::binary, value::size(size)>>
value, acc -> <<acc::binary, value>>
end)
end
def sample(ast, _opts), do: ast
end
[
{quote(do: :foo), &is_atom/1},
{quote(do: "foo"), &is_binary/1},
{quote(do: <<1::3>>), &is_bitstring/1},
{quote(do: true), &is_boolean/1},
{quote(do: %RuntimeError{}), &is_exception/1},
{quote(do: %RuntimeError{}), &is_exception(&1, RuntimeError)},
{quote(do: 1.2), &is_float/1},
{quote(do: 1), &is_integer/1},
{quote(do: [1, 2, 3]), &is_list/1},
{quote(do: %{foo: "bar"}), &is_map/1},
{quote(do: %{foo: "bar"}), &is_map_key(&1, :foo)},
{quote(do: nil), &is_nil/1},
{quote(do: 1), &is_number/1},
{quote(do: %URI{path: "/"}), &is_struct/1},
{quote(do: %URI{path: "/"}), &is_struct(&1, URI)},
{quote(do: {1, 2, 3, 4}), &is_tuple/1}
]
|> Enum.map(fn {quoted, func} ->
quoted
|> Example.sample()
|> func.()
|> dbg()
end)
You can rewrite this code to create functions like is_map_ast/1
, is_struct_ast/2
and so on …
Also you need to be careful as not everything can be converted to quoted expression, see: Quote and unquote - The Elixir programming language for more information.