How to get AST (Abstract Syntax Tree) of an Erlang local fun?

1k Views Asked by At

For some Erlang terms for example atom, tuple, list i can get AST using erl_parse:abstract/1. But it does not work for funs.

~ $ erl
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V8.0  (abort with ^G)

1> erl_parse:abstract(foo).
{atom,0,foo}

2> erl_parse:abstract([bar]).
{cons,0,{atom,0,bar},{nil,0}}

3> erl_parse:abstract({baz}).
{tuple,0,[{atom,0,baz}]}

4> erlang:fun_info(fun() -> ok end, type).
{type,local} % So this is a local fun

5> erl_parse:abstract(fun() -> ok end).       
** exception error: no function clause matching 
                    erl_parse:abstract(#Fun<erl_eval.20.52032458>,0,
                                       #Fun<erl_parse.3.3133389>) (erl_parse.yrl, line 1330)

I know that some local funs have their AST in their info. But this is not for all local funs.

~ $ erl
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]
Eshell V8.0  (abort with ^G)

1> erlang:fun_info(fun() -> ok end, env).
{env,[{[],
       {eval,#Fun<shell.21.31625193>},
       {value,#Fun<shell.5.31625193>},
       [{clause,1,[],[],[{atom,1,ok}]}]}]} %% Here

2> foo:test(). %% Yields a fun
#Fun<foo.0.10202683>

3> erlang:fun_info(foo:test(), type).
{type,local} %% So this is a local fun too

4> erlang:fun_info(foo:test(), env). 
{env,[]} %% : (

Getting AST of an external fun is not hard. my solution is to load its module beam chunks and get AST of that function. If you have better solution, please tell me. The main problem is for getting AST of local funs.

2

There are 2 best solutions below

1
On

erl_parse:abstract/1 cannot accept function object as argument. I think you are right in the rest.

0
On

Maybe you can try also combine erl_scan:string/1 and erl_parse:parse_exprs/1, eg:

1> Fun = "fun() -> ok end.".
"fun() -> ok end."
2> {ok, Tokens, _EndLocation} = erl_scan:string(Fun).
{ok,[{'fun',1},
     {'(',1},
     {')',1},
     {'->',1},
     {atom,1,ok},
     {'end',1},
     {dot,1}],
    1}
3> {ok, ExprList} = erl_parse:parse_exprs(Tokens).
{ok,[{'fun',1,{clauses,[{clause,1,[],[],[{atom,1,ok}]}]}}]}

Hope, this will be helpful.