Current section
Files
Jump to
Current section
Files
lib/sibyl/ast.ex
defmodule Sibyl.AST do
@moduledoc """
Utility module for working with ASTs
"""
@type ast() :: term()
@type alias() :: {:__aliases__, term(), [atom()]}
@type unused() :: :__unused__
@doc """
Returns true if the given argument is an Elixir AST node representing a module alias
such as `Enum`.
"""
defguard alias?(ast) when is_tuple(ast) and elem(ast, 0) == :__aliases__
@doc """
Returns true if the given argument is equal to `:__unused__`. Primarily used internally.
"""
defguard unused?(term) when term == :__unused__
@doc """
Returns the `:__unused__` atom.
"""
@spec unused() :: ast()
defmacro unused do
quote do
:__unused__
end
end
# coveralls-ignore-start
# TODO: find a way to unit test this, as we now expect the macro's env to be
# passed in
@doc """
Given an alias AST node, returns the fully resolved alias that said node would expand
to.
For example, given: `{:__aliases, unused(), [Elixir, Enum]}`, returns: `Enum`.
"""
@spec module(alias(), Macro.Env.t()) :: module()
def module({:__aliases__, _metadata, _module_list} = ast, env) do
case Macro.expand(ast, env) do
module when is_atom(module) ->
module
otherwise ->
otherwise = inspect(otherwise)
raise ArgumentError, "expected an alias expanding to a module, got: #{otherwise}"
end
end
end