Skip to content

Instantly share code, notes, and snippets.

@vinoski
Created January 27, 2013 14:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vinoski/4648621 to your computer and use it in GitHub Desktop.
Save vinoski/4648621 to your computer and use it in GitHub Desktop.
Another version of the get_all_bindings parse transform (see https://gist.github.com/4643721), but using erl_syntax and erl_syntax_lib.
-module(get_all_bindings2).
-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.
%%
%% This version makes some use of erl_syntax and erl_syntax_lib, though
%% probably not to their fullest extent. My original version does its own
%% digging through the Abstract Format forms (see it here:
%% https://gist.github.com/4643721).
parse_transform(Forms, _Options) ->
do_replace([{erl_syntax:type(F), F} || F <- Forms], []).
do_replace([{function, Fun}|Forms], Acc) ->
Tree = erl_syntax_lib:annotate_bindings(Fun, []),
NewFun = case erl_syntax_lib:fold(fun fold_app/2, [], Tree) of
[] ->
Fun;
AllVars ->
replace_calls(Fun, AllVars)
end,
do_replace(Forms, [NewFun|Acc]);
do_replace([{_,Form}|Forms], Acc) ->
do_replace(Forms, [Form|Acc]);
do_replace([], Acc) ->
lists:reverse(Acc).
fold_app(Tree, Acc) ->
case erl_syntax:type(Tree) of
application ->
case erl_syntax_lib:analyze_application(Tree) of
{get_all_bindings,1} ->
{env, Vars} = lists:keyfind(env, 1, erl_syntax:get_ann(Tree)),
[Vars|Acc];
_ ->
Acc
end;
_ ->
Acc
end.
replace_calls({function,L,Nm,Ar,[{clause,CL,Args,G,Body}]}, AllVars) ->
NewBody = replace_calls(Body, AllVars, []),
{function,L,Nm,Ar,[{clause,CL,Args,G,NewBody}]}.
replace_calls([{call,L,{atom,L2,get_all_bindings},_}|Forms], [Vars|AllVars], Acc) ->
Bindings = lists:foldl(fun(A,Acc1) ->
V={tuple,L2,[{atom,L2,A},
{var,L2,A}]},
{cons,L2,V,Acc1}
end, {nil,L2}, Vars),
NewCall = {call,L,{atom,L2,get_all_bindings},[Bindings]},
replace_calls(Forms, AllVars, [NewCall|Acc]);
replace_calls([Form|Forms], AllVars, Acc) ->
replace_calls(Forms, AllVars, [Form|Acc]);
replace_calls([], _, Acc) ->
lists:reverse(Acc).
@vinoski
Copy link
Author

vinoski commented Jan 29, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment