|
| 1 | +-module(wf_lazy_coalesce). |
| 2 | +-export([parse_transform/2]). |
| 3 | + |
| 4 | +%% This module is the parse transform for the lazy_coalesce process |
| 5 | + |
| 6 | +parse_transform(Forms, _Options) -> |
| 7 | + %dump_forms("lazy.forms", Forms), |
| 8 | + Forms2 = process_forms(Forms), |
| 9 | + %dump_forms("lazy.newforms", Forms2), |
| 10 | + Forms2. |
| 11 | + |
| 12 | +%dump_forms(File, Forms) when is_list(Forms) -> |
| 13 | +% FormattedForms = [format_forms(F) || F <- Forms], |
| 14 | +% file:write_file(File, FormattedForms). |
| 15 | +% |
| 16 | +%format_forms(X) -> |
| 17 | +% io_lib:format("~p.~n~n", [X]). |
| 18 | + |
| 19 | +process_forms(Forms) when is_list(Forms) -> |
| 20 | + [process_forms(F) || F <- Forms]; |
| 21 | +process_forms(Form) when is_tuple(Form) -> |
| 22 | + case process_form(Form) of |
| 23 | + {ok, NewForm} -> |
| 24 | + NewForm; |
| 25 | + no_change -> |
| 26 | + List = tuple_to_list(Form), |
| 27 | + ProcessedList = process_forms(List), |
| 28 | + list_to_tuple(ProcessedList) |
| 29 | + end; |
| 30 | +process_forms(Form) -> |
| 31 | + Form. |
| 32 | + |
| 33 | +process_form({call, LN, {remote, LN2, {atom, LN3, wf}, {atom, LN4, lazy_coalesce}}, [Args = {cons, _, _, _}] }) -> |
| 34 | + WrappedArgs = wrap_args(Args), |
| 35 | + %io:format("Wrapping wf:lazy_coalesce on ~p~n",[LN4]), |
| 36 | + NewForm = {call, LN, {remote, LN2, {atom, LN3, wf}, {atom, LN4, eval_coalesce}}, [WrappedArgs] }, |
| 37 | + {ok, NewForm}; |
| 38 | +process_form({call, LN, {remote, LN2, {atom, LN3, wf}, {atom, LN4, lazy_coalesce}}, Args = [_] }) -> |
| 39 | + {Line, Col} = case LN of |
| 40 | + {L, C} -> {L, C}; |
| 41 | + L -> {L, 0} |
| 42 | + end, |
| 43 | + logger:warning("Call to wf:lazy_coalesce at line ~p (column ~p) is not explicitly listing each argument.~nThis cannot be made lazy. Converting it to the plain wf:coalesce/1~n", [Line, Col]), |
| 44 | + NewForm = {call, LN, {remote, LN2, {atom, LN3, wf}, {atom, LN4, coalesce}}, Args }, |
| 45 | + {ok, NewForm}; |
| 46 | +process_form(_X) -> |
| 47 | + no_change. |
| 48 | + %% if it's not one of the above things, then dive into it to process it. |
| 49 | + %{no_change, X}. |
| 50 | + |
| 51 | +wrap_args({cons, LN, H, T}) -> |
| 52 | + %io:format("Found a cons...~n"), |
| 53 | + H2 = wrap_arg(H), |
| 54 | + T2 = wrap_args(T), |
| 55 | + {cons, LN, H2, T2}; |
| 56 | +wrap_args(Nil = {nil, _}) -> |
| 57 | + %io:format("End of List~n"), |
| 58 | + Nil. |
| 59 | + |
| 60 | +wrap_arg(Arg = {Type, _, _}) when Type==var; |
| 61 | + Type==atom; |
| 62 | + Type==integer; |
| 63 | + Type==string; |
| 64 | + Type==binary; |
| 65 | + Type==iolist -> |
| 66 | + %% This is a simple term, we can safely pass it through, as wrapping a Fun around it would be more overhead for the VM during runtime |
| 67 | + %io:format("Simple Arg (~p). Nothing to format...~n", [Arg]), |
| 68 | + Arg; |
| 69 | +wrap_arg(Arg) when is_tuple(Arg) -> |
| 70 | + LN = element(2, Arg), |
| 71 | + ClauseArgs = [], |
| 72 | + Guards = [], |
| 73 | + Clause = {clause, LN, ClauseArgs, Guards, [Arg]}, |
| 74 | + %io:format("Wrapping Arg: ~p~n",[Arg]), |
| 75 | + WrappedArg = {'fun', LN, {clauses, [Clause]}}, |
| 76 | + WrappedArg. |
0 commit comments