-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