Skip to content

Instantly share code, notes, and snippets.

@vinoski
Created December 11, 2012 20:37
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/4261933 to your computer and use it in GitHub Desktop.
Save vinoski/4261933 to your computer and use it in GitHub Desktop.
parse transform to make exported functions call internal async versions
-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.
@gburd
Copy link

gburd commented Dec 12, 2012

Neat stuff. :-) Were you going to incorporate this into something?

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