Packages
croma
0.4.7
0.13.0
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.3
0.7.2
0.7.1
0.7.0
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Elixir macro utilities to make type-based programming easier
Current section
Files
Jump to
Current section
Files
lib/croma/type_util.ex
defmodule Croma.TypeUtil do
@moduledoc """
Utilities to work with internal representation of types.
"""
alias Kernel.Typespec
@primitive_types [
:pid,
:port,
:reference,
:atom,
:binary,
:bitstring,
:boolean,
:byte,
:char,
:integer,
:pos_integer,
:neg_integer,
:non_neg_integer,
:float,
:number,
:list,
:tuple,
:map,
:fun,
]
@spec resolve_primitive(module, atom) :: {:ok, atom} | :error
def resolve_primitive(module, name) do
case Typespec.beam_types(module) do
nil -> # No beam file is available
try do
[:type, :typep, :opaque]
|> Enum.flat_map(&Module.get_attribute(module, &1))
|> Enum.find(&match?({_, {:::, _, [{^name, _, _}, _ast]}, _}, &1))
|> case do
nil -> :error
{_, type_ast, env} -> destructure_type_expr(module, type_ast, env)
end
rescue
_ -> :error
end
types ->
case Enum.find(types, &match?({_, {^name, _, _}}, &1)) do
nil -> :error
{_, type_expr} -> destructure_type_expr(module, Typespec.type_to_ast(type_expr), nil)
end
end
end
defp destructure_type_expr(module, {:::, _, [_lhs, type_ast]}, env) do
case type_ast do
{_, _} -> {:ok, :tuple} # 2-tuple is special in elixir AST
{:{} , _, _} -> {:ok, :tuple}
{:%{}, _, _} -> {:ok, :map}
{:% , _, _} -> {:ok, :map} # struct
{t , _, _} -> destructure_type_expr2(module, t, env)
[{:->, _, _}] -> {:ok, :fun}
l when is_list(l) -> {:ok, :list}
_other -> :error
end
end
defp destructure_type_expr2(module, t, env) do
case t do
t when t in @primitive_types -> {:ok, t}
a when is_atom(a) -> resolve_primitive(module, a)
{:., _, [mod, n]} ->
mod_expanded = if env, do: Macro.expand(mod, env), else: mod
resolve_primitive(mod_expanded, n)
end
end
def list_to_type_union([v ]), do: v
def list_to_type_union([h | t]), do: {:|, [], [h, list_to_type_union(t)]}
end