-module(astdemo). -export([hello/0, hello/2]). hello() -> hello("world", 1). hello(_What, 0) -> ok; hello(What, Count) -> io:format("Hello, ~s~n", [What]), hello(What, Count - 1).   Eshell V5.8.5 (abort with ^ G)
 1> {ok, Forms} = epp: parse_file ("astdemo.erl", [], []), io: format ("~ p ~ n", [Forms]).
 [{attribute, 1, file, {"astdemo.erl", 1}},
  {attribute, 1, module, astdemo},
  {attribute, 2, export, [{hello, 0}, {hello, 2}]},
  {function, 4, hello, 0,
            [{clause, 4, [], [],
                     [{call, 5,
                            {atom, 5, hello},
                            [{string, 5, "world"}, {integer, 5,1}]}]}]],
  {function, 7, hello, 2,
            [{clause, 7, [{var, 7, '_ What'}, {integer, 7.0}], [], [{atom, 8, ok}]},
             {clause, 9,
                     [{var, 9, 'What'}, {var, 9, 'Count'}],
                     [],
                     [{call, 10,
                            {remote, 10, {atom, 10, io}, {atom, 10, format}},
                            [{string, 10, "Hello, ~ s ~ n"},
                             {cons, 10, {var, 10, 'What'}, {nil, 10}}]},
                      {call, 11,
                            {atom, 11, hello},
                            [{var, 11, 'What'},
                             {op, 11, '-', {var, 11, 'Count'}, {integer, 11,1}}]}]}]},
  {eof, 12}]
 ok
 -module(demo_pt). -export([parse_transform/2]). parse_transform(Forms, _Options) -> io:format("~p~n", [Forms]), Forms.  -module(astdemo). -compile({parse_transform, demo_pt}). -export([hello/0, hello/2]). ...........   Eshell V5.8.5 (abort with ^ G)
 1> c (astdemo).
 [{attribute, 1, file, {"./ astdemo.erl", 1}},
  {attribute, 1, module, astdemo},
  {attribute, 3, export, [{hello, 0}, {hello, 2}]},
  {function, 5, hello, 0,
            [{clause, 5, [], [],
                     [{call, 6,
                            {atom, 6, hello},
                            [{string, 6, "world"}, {integer, 6,1}]}]}]},
  {function, 8, hello, 2,
            [{clause, 8, [{var, 8, '_ What'}, {integer, 8.0}], [], [{atom, 9, ok}]},
             {clause, 10,
                     [{var, 10, 'What'}, {var, 10, 'Count'}],
                     [],
                     [{call, 11,
                            {remote, 11, {atom, 11, io}, {atom, 11, format}},
                            [{string, 11, "Hello, ~ s ~ n"},
                             {cons, 11, {var, 11, 'What'}, {nil, 11}}]},
                      {call, 12,
                            {atom, 12, hello},
                            [{var, 12, 'What'},
                             {op, 12, '-', {var, 12, 'Count'}, {integer, 12,1}}]}]}]},
  {eof, 13}]
 {ok, astdemo}  % hello_to_hi replaces occurences of hello/0 with hi/0 hello_to_hi({attribute, Line, export, Exports}) -> % export attribute. Replace {hello, 0} with {hi, 0} HiExports = lists:map( fun ({hello, 0}) -> {hi, 0}; (E) -> E end, Exports), {attribute, Line, export, HiExports}; hello_to_hi({function, Line, hello, 0, Clauses}) -> % Header of hello/0. Just replace hello with hi {function, Line, hi, 0, Clauses}; hello_to_hi(Form) -> % Default: do not modify form Form.  parse_transform(Forms, _Options) -> HiForms = lists:map(fun hello_to_hi/1, Forms), io:format("~p~n", [HiForms]), HiForms.   Eshell V5.8.5 (abort with ^ G)
 1> c (astdemo).
 [{attribute, 1, file, {"./ astdemo.erl", 1}},
  {attribute, 1, module, astdemo},
  {attribute, 3, export, [{hi, 0}, {hello, 2}]},
  {function, 5, hi, 0,
            [{clause, 5, [], [],
                     [{call, 6,
                            {atom, 6, hello},
                            [{string, 6, "world"}, {integer, 6,1}]}]}]},
  {function, 8, hello, 2,
            [{clause, 8, [{var, 8, '_ What'}, {integer, 8.0}], [], [{atom, 9, ok}]},
             {clause, 10,
                     [{var, 10, 'What'}, {var, 10, 'Count'}],
                     [],
                     [{call, 11,
                            {remote, 11, {atom, 11, io}, {atom, 11, format}},
                            [{string, 11, "Hello, ~ s ~ n"},
                             {cons, 11, {var, 11, 'What'}, {nil, 11}}]},
                      {call, 12,
                            {atom, 12, hello},
                            [{var, 12, 'What'},
                             {op, 12, '-', {var, 12, 'Count'}, {integer, 12,1}}]}]}]},
  {eof, 13}]
 {ok, astdemo}
 2> astdemo: hi ().
 Hello, world
 ok  handle_call(Request, From, State) -> ..... {reply,Reply,NewState}.  handle_call(Request, From) -> ..... Reply.  -module(sl_gs_demo). -behavior(gen_server). -compile({parse_transform, sl_gs}). -export([handle_call/2, ref_handle_call/3]). -export([handle_cast/2, handle_info/2]). -export([init/1, terminate/2, code_change/3]). % This will be transformed handle_call(Req, From) -> {Req, From}. % That's what handle_call should finally look like ref_handle_call(Req, From, State) -> {reply, {Req, From}, State}. % Dummy functions to make gen_server happy % Exercise: Try to insert them automatically during transformations :) handle_cast(_, State) -> {noreply, State}. handle_info(_, State) -> {noreply, State}. init(_) -> {ok, none}. terminate(_, _) -> ok. code_change(_, State, _) -> {ok, State}.  -module(sl_gs). -export([parse_transform/2]). parse_transform(Forms, _Options) -> lists:map(fun add_missing_state/1, Forms). add_missing_state({attribute, Line, export, Exports}) -> % export attribute. Replace {handle_call, 2} with {handle_call, 3} NewExports = lists:map( fun ({handle_call, 2}) -> {handle_call, 3}; % You can add more clauses here for other function mutations (E) -> E end, Exports), {attribute, Line, export, NewExports}; add_missing_state({function, Line, handle_call, 2, Clauses}) -> % Mutate clauses NewClauses = lists:map(fun change_call_clause/1, Clauses), % Finally, change arity in header {function, Line, handle_call, 3, NewClauses}; add_missing_state(Form) -> % Default Form. change_call_clause({clause, Line, Arguments, Guards, Body}) -> % Change arity in clauses. NewArgs = Arguments ++ [{var, Line, 'State'}], % Add State argument % Then replace last statement of each clause with corresponding tuple NewBody = change_call_body(Body), {clause, Line, NewArgs, Guards, NewBody}. change_call_body([Statement | Rest=[_|_] ]) -> % Rest has to be non-empty list for this % Recurse to change only last statement [Statement|change_call_body(Rest)]; change_call_body([LastStatement]) -> % Put it into tuple. Lines are zero to omit parsing LastStatement [{tuple,0, [{atom,0,reply}, LastStatement, {var,0,'State'}] }].   Eshell V5.8.5 (abort with ^ G)
 1> c (sl_gs_demo).
 {ok, sl_gs_demo}
 2> {ok, D} = gen_server: start_link (sl_gs_demo, [], []).
 {ok, <0.39.0>}
 3> gen_server: call (D, hello).
 {hello, {<0.32.0>, # Ref <0.0.0.83>}}
Source: https://habr.com/ru/post/140374/
All Articles