Current section
Files
Jump to
Current section
Files
lib/parser.ex
defmodule Argx.Parser do
@moduledoc false
alias Argx.Const, as: Con
@allowed_fun_types Con.allowed_fun_types()
@allowed_types Con.allowed_types()
@names_key Con.names_key()
###
def parse_fun(block) do
block |> _parse_fun(%{})
end
defp _parse_fun({type, _, fun}, acc) when type in @allowed_fun_types do
fun |> _parse_fun(acc)
end
defp _parse_fun([{:when, _, fa_guard}, [{:do, block}]], acc) do
fa_guard
|> _parse_fun(acc)
|> Map.put(:block, block)
end
defp _parse_fun([fa, [{:do, block}]], acc) do
fa
|> _parse_fun(acc)
|> Map.put(:block, block)
|> Map.put(:guard, true)
end
defp _parse_fun([fa, guard], acc) do
fa
|> _parse_fun(acc)
|> Map.put(:guard, guard)
end
defp _parse_fun({f, _, [{_, _, nil} | _] = a}, acc) do
acc
|> Map.put(:f, f)
|> Map.put(:a, a)
end
defp _parse_fun({f, _, nil}, acc) do
acc
|> Map.put(:f, f)
|> Map.put(:a, [])
end
defp _parse_fun(_, _) do
nil
end
###
def parse_configs({:configs, _, [_ | _] = configs}) do
configs |> _parse_configs(%{})
end
def parse_configs([_ | _] = configs) do
configs |> _parse_configs(%{})
end
def parse_configs(configs) do
[configs] |> _parse_configs(%{})
end
def _parse_configs([], acc) do
acc
end
def _parse_configs([{:__aliases__, _, [defconfig_name]} | rest], acc) do
{_, acc} =
Map.get_and_update(acc, @names_key, fn current ->
new_value = (current && [defconfig_name | current]) || [defconfig_name]
{current, new_value}
end)
rest |> _parse_configs(acc)
end
def _parse_configs([config | rest], acc) do
config_map = config |> every_config()
acc = acc |> Map.merge(config_map)
rest |> _parse_configs(acc)
end
defp every_config({:||, _, [{field, _, items}, default]}) do
_every_config(field, items, default)
end
defp every_config({field, _, items}) do
_every_config(field, items)
end
defp _every_config(field, items, default \\ nil) do
config = %Argx.Config{
auto: false,
optional: false,
type: nil,
range: nil,
default: default
}
items = every_item(items, config)
Map.put(%{}, field, items)
end
defp every_item([], acc) do
acc
end
defp every_item([type | rest], acc) when type in @allowed_types do
acc = Map.put(acc, :type, type)
rest |> every_item(acc)
end
defp every_item([:optional | rest], acc) do
acc = Map.put(acc, :optional, true)
rest |> every_item(acc)
end
defp every_item([:auto | rest], acc) do
acc = Map.put(acc, :auto, true)
rest |> every_item(acc)
end
defp every_item([{:.., _, [_, _]} = range | rest], acc) do
acc = Map.put(acc, :range, range)
rest |> every_item(acc)
end
defp every_item([range | rest], acc) when is_integer(range) do
acc = Map.put(acc, :range, range)
rest |> every_item(acc)
end
###
def parse_defconfig_name({:__aliases__, _, [name]}) do
name
end
def parse_defconfig_name(_) do
:ignore
end
def parse_range(value) when is_number(value), do: [value, value]
def parse_range({:.., _, [l, r]}), do: [l, r]
end