-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