Created
December 11, 2012 20:37
-
-
Save vinoski/4261933 to your computer and use it in GitHub Desktop.
parse transform to make exported functions call internal async versions
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(pt_async). | |
-export([parse_transform/2]). | |
parse_transform(AST, _Options) -> | |
asyncify_funs(AST, []). | |
%% Search for functions whose bodies simply return the atom "async" (minus | |
%% the quotes of course). Replace that body with a call to the async | |
%% version of the called function, passing a ref as well. The async function | |
%% (assuming it succeeds) passes the result back as a message, which the | |
%% initial function receives and processes to return a result. The async | |
%% function is also generated here, since it's just a NIF stub. | |
asyncify_funs([], Acc) -> | |
lists:reverse(Acc); | |
asyncify_funs([{function,L,FName,Arity,Body}=Fun|T], Acc) -> | |
asyncify_funs( | |
T, | |
case Body of | |
[{clause,CL,Args,Guards,[{atom,_,async}]}] -> | |
NFName = list_to_atom("async_"++atom_to_list(FName)), | |
AsyncArgs = [{var,CL+3,'Ref'}|Args], | |
NL = L+10, | |
[ | |
{function,NL,NFName,Arity+1, | |
[{clause,NL+1, | |
[leading_underscore(A,NL+1) || A <- AsyncArgs], | |
[], | |
[{call,NL+2,{remote,NL+2,{atom,NL+2,erlang}, | |
{atom,NL+2,nif_error}}, | |
[{tuple,NL+2,[{atom,NL+2,error},{atom,NL+2,not_loaded}]}]}]} | |
]}, | |
{function,L,FName,Arity, | |
[{clause,CL,Args,Guards, | |
[{call,CL+1,{remote,CL+1, | |
{atom,CL+1,scheduler_bump}, | |
{atom,CL+1,big}},[]}, | |
{match,CL+2,{var,CL+2,'Ref'}, | |
{call,CL+1,{atom,CL+1,make_ref},[]}}, | |
{'case',CL+3, | |
{call,CL+3,{atom,CL+3,NFName},AsyncArgs}, | |
[{clause,CL+4,[{atom,CL+4,ok}],[], | |
[{'receive',CL+5, | |
[{clause,CL+6, | |
[{tuple,CL+6,[{var,CL+6,'Ref'}, | |
{var,CL+6,'Result'}]}], | |
[], | |
[{var,CL+7,'Result'}]}]}]}, | |
{clause,CL+8,[{var,CL+8,'Error'}],[], | |
[{var,CL+9,'Error'}]}]}]}]} | Acc]; | |
_ -> | |
[Fun|Acc] | |
end); | |
asyncify_funs([H|T], Acc) -> | |
asyncify_funs(T, [H|Acc]). | |
leading_underscore({var,_,Name},Line) -> | |
case atom_to_list(Name) of | |
"_" -> | |
error("do not use plain underscores for async function arguments"); | |
[$_|_] -> | |
{var,Line,Name}; | |
AName -> | |
{var,Line,list_to_atom("_"++AName)} | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Neat stuff. :-) Were you going to incorporate this into something?