public
Last active

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.

  • Download Gist
get_all_bindings.erl
Erlang
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
-module(get_all_bindings).
-export([parse_transform/2]).
-author('Steve Vinoski <vinoski@ieee.org>').
 
%% 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.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.