Last active
December 11, 2015 18:48
-
-
Save vinoski/4643721 to your computer and use it in GitHub Desktop.
This parse transform looks for a plain call to get_all_bindings/1 within each function body within the module being processed and if found replaces its argument with a list of {variable name, value} tuples, one for each variable used in the function body up to the call point. The module must contain its own suitable definition for the get_all_bi…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(get_all_bindings). | |
-export([parse_transform/2]). | |
-author('Steve Vinoski <[email protected]>'). | |
%% This parse transform looks for a plain call to get_all_bindings/1 within | |
%% each function body within the module being processed and if found | |
%% replaces its argument with a list of {variable name, value} tuples, one | |
%% for each variable used in the function body up to the call point. The | |
%% module must contain its own suitable definition for the | |
%% get_all_bindings/1 function. | |
parse_transform(Forms, _Options) -> | |
handle_forms(Forms, []). | |
handle_forms([], Acc) -> | |
lists:reverse(Acc); | |
handle_forms([{function,L,Nm,Ar,[{clause,CL,Args,G,Body}]}|Forms], Acc) -> | |
NewBody = replace_get_all_bindings(Args, Body), | |
NewFun = {function,L,Nm,Ar,[{clause,CL,Args,G,NewBody}]}, | |
handle_forms(Forms, [NewFun|Acc]); | |
handle_forms([Form|Forms], Acc) -> | |
handle_forms(Forms, [Form|Acc]). | |
replace_get_all_bindings(Args, Body) -> | |
get_all_bindings(Body, find_vars(Args, sets:new())). | |
get_all_bindings(Forms, Vars) -> | |
get_all_bindings(Forms, Vars, false, []). | |
get_all_bindings([], _, _, Acc) -> | |
lists:reverse(Acc); | |
get_all_bindings([{call,CL1,{atom,CL2,get_all_bindings},_}|Forms], | |
Vars, false, Acc) -> | |
Bindings = lists:foldl(fun(A,Acc1) -> | |
V={tuple,CL1,[{atom,CL1,A}, | |
{var,CL1,A}]}, | |
{cons,CL1,V,Acc1} | |
end, {nil,CL1}, sets:to_list(Vars)), | |
NewCall = {call,CL1,{atom,CL2,get_all_bindings},[Bindings]}, | |
get_all_bindings(Forms, Vars, true, [NewCall|Acc]); | |
get_all_bindings([Form|Forms], Vars, false, Acc) -> | |
get_all_bindings(Forms, find_vars(Form, Vars), false, [Form|Acc]); | |
get_all_bindings([Form|Forms], Vars, true, Acc) -> | |
get_all_bindings(Forms, Vars, true, [Form|Acc]). | |
find_vars([{'fun',_,_}|Vals], Acc) -> | |
find_vars(Vals, Acc); | |
find_vars([{var,_,Val}|Vals], Acc) -> | |
find_vars(Vals, sets:add_element(Val, Acc)); | |
find_vars([{_,_,_}|Vals], Acc) -> | |
find_vars(Vals, Acc); | |
find_vars([var,_,Val|Vals], Acc) -> | |
find_vars(Vals, sets:add_element(Val, Acc)); | |
find_vars(['fun',_,_|Vals], Acc) -> | |
find_vars(Vals, Acc); | |
find_vars([Val|Vals], Acc) when is_tuple(Val) -> | |
find_vars(Vals, find_vars(tuple_to_list(Val), Acc)); | |
find_vars([[Val0|Val1]|Vals], Acc) -> | |
find_vars([Val1,Vals], find_vars(Val0, Acc)); | |
find_vars([_|Vals], Acc) -> | |
find_vars(Vals, Acc); | |
find_vars([], Acc) -> | |
Acc; | |
find_vars(Val, Acc) when is_tuple(Val) -> | |
find_vars(tuple_to_list(Val), Acc); | |
find_vars(_, Acc) -> | |
Acc. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also https://gist.github.com/4648621