Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dirty macro warning + auto arity support #110

Merged
merged 11 commits into from
Feb 26, 2024
Merged
40 changes: 36 additions & 4 deletions lib/unifex/specs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,26 +70,58 @@ defmodule Unifex.Specs do
{_res, binds} = Code.eval_string(specs_code, [{:unifex_config__, []}], make_env(specs_file))
config = binds |> Keyword.fetch!(:unifex_config__) |> Enum.reverse()

{functions_args, functions_results} =
{functions_args_arity, functions_results} =
config
|> Keyword.get_values(:function)
|> Enum.map(fn {name, args, results} -> {{name, args}, {name, results}} end)
|> Enum.map(fn {name, args, results} ->
{{{name, args}, {name, Enum.count(args)}}, {name, results}}
end)
|> Enum.unzip()

{functions_args, functions_arity} = Enum.unzip(functions_args_arity)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{functions_args, functions_arity} = Enum.unzip(functions_args_arity)
functions_arity = Enum.map(functions_args, fn {name, args} -> {name, Enum.count(args)} end)

You don't have to create functions_args_arity variable, you can just create function_args the way it has been done before your changes and create functions_arity with a simple Enum.map, without second call of Enum.unzip, IMO it will simplify your code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after changes suggested by @mat-hek this is no longer necessary


functions_results =
Enum.flat_map(functions_results, fn {name, results} -> Enum.map(results, &{name, &1}) end)

functions_docs = parse_docs(config, specs_file)

dirty_functions =
config
|> Keyword.get_values(:dirty_functions)
|> List.flatten()
|> Enum.map(fn {dirty_func, type} ->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of map and reject, use flat_map

{dirty_name, dirty_arity} =
cond do
is_tuple(dirty_func) ->
dirty_func

is_atom(dirty_func) ->
{dirty_func, nil}
end

{matched_name, matched_arity} = List.keyfind(functions_arity, dirty_name, 0, {nil, nil})

if matched_name == dirty_name and (matched_arity == dirty_arity or dirty_arity == nil) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{dirty_name, dirty_arity} =
cond do
is_tuple(dirty_func) ->
dirty_func
is_atom(dirty_func) ->
{dirty_func, nil}
end
{matched_name, matched_arity} = List.keyfind(functions_arity, dirty_name, 0, {nil, nil})
if matched_name == dirty_name and (matched_arity == dirty_arity or dirty_arity == nil) do
dirty_name =
case dirty_func do
{name, _arity} -> name
name -> name
end
{matched_name, matched_args} = List.keyfind(functions_args, dirty_name, 0, {nil, nil})
if dirty_func in [matched_name, {matched_name, length(matched_args)}] do

slightly more idiomatic, and you don't need functions_arity

{{dirty_name, matched_arity}, type}
else
Logger.warning(
"Function #{dirty_name} marked as dirty does not match any function defined in spec (#{specs_file})."
)

nil
end
end)
|> Enum.reject(fn el -> el == nil end)
|> Map.new()

%__MODULE__{
name: name,
module: Keyword.get(config, :module),
functions_args: functions_args,
functions_results: functions_results,
functions_docs: functions_docs,
sends: Keyword.get_values(config, :sends),
dirty_functions:
config |> Keyword.get_values(:dirty_functions) |> List.flatten() |> Map.new(),
dirty_functions: dirty_functions,
callbacks: config |> Keyword.get_values(:callback) |> Map.new(),
interface: Keyword.get(config, :interface),
state_type: Keyword.get(config, :state_type, nil),
Expand Down