Created
January 27, 2013 14:35
-
-
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.
This file contains 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_bindings2). | |
-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. | |
%% | |
%% 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). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also https://gist.github.com/4643721