HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table...
Transcript of HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table...
![Page 1: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/1.jpg)
HERE BE DRAGONS
charting parse transforms in Erlang 1 / 84
![Page 2: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/2.jpg)
What is a parsetransform? Erlang Manual:
Programmers are strongly advised not to engage in parse transformsand no support is offered for problems encountered.
Our journey
2 / 84
![Page 3: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/3.jpg)
What is a parsetransform?
Program as data
The Abstract Format
Our journey
3 / 84
![Page 4: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/4.jpg)
What is a parsetransform?
Program as data
Working withAbstract Format
Bring your sword to the dragon fight
Our journey
4 / 84
![Page 5: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/5.jpg)
Our journey
What is a parsetransform?
Program as data
Working withAbstract Format
Parse transforms inthe wild
Other monsters in the menagerie
5 / 84
![Page 6: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/6.jpg)
Our journey
What is a parsetransform?
Program as data
Working withAbstract Format
Parse transforms inthe wild
Inline parsetransform
Have the dragon eat it's own tail
6 / 84
![Page 7: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/7.jpg)
What is a parse transform?
7 / 84
![Page 8: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/8.jpg)
Source
↓
Compiler
↓
Executable
module.erl
↓
> erlc module.erl
↓
module.beam
8 / 84
![Page 9: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/9.jpg)
1. Expand macros2. Lex3. Parse4. Abstract syntax tree5. Optimize6. Generate bytecode
Classic compilation steps
9 / 84
![Page 10: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/10.jpg)
Classic compilation steps1. Expand macros2. Lex3. Parse4. Abstract syntax tree5. → Transformed syntax tree = your_function(AST) ←6. Optimize7. Generate bytecode
10 / 84
![Page 11: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/11.jpg)
Identity transform-module(my_transform).
-export([parse_transform/2]).
parse_transform(Forms, Options) -> Forms.
11 / 84
![Page 12: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/12.jpg)
Invoke a parse transformerlc
erlc my_transform.erlerlc -pa . +"{parse_transform,my_transform}" test.erl
rebar.config
{erl_opts, [ {parse_transform, my_transform} ]}.
module inline
-module(test).
-compile([{parse_transform, my_transform}]).
...
12 / 84
![Page 13: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/13.jpg)
Abstract FormatYour program as data
13 / 84
![Page 14: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/14.jpg)
A + B * C
Abstract Syntax Tree
14 / 84
![Page 15: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/15.jpg)
A + B * C (A + B) * C
Abstract Syntax Tree
15 / 84
![Page 16: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/16.jpg)
A + B * C
{'+', A, {'*', B, C}}
(A + B) * C
{'*', {'+', A, B}, C}
Abstract Syntax Tree
16 / 84
![Page 17: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/17.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
17 / 84
![Page 18: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/18.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
18 / 84
![Page 19: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/19.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
19 / 84
![Page 20: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/20.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
20 / 84
![Page 21: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/21.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
21 / 84
![Page 22: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/22.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
22 / 84
![Page 23: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/23.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
23 / 84
![Page 24: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/24.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
24 / 84
![Page 25: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/25.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
25 / 84
![Page 26: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/26.jpg)
-module(test).
-compile([{parse_transform, my_transform}]).
-export([hello/1]).
hello(Who) -> io:fwrite("hello ~p", [Who]).
[{attribute,1,file,{"test.erl",1}}, {attribute,1,module,test}, {attribute,3,compile,[]}, {attribute,5,export,[{hello,1}]}, {function,7,hello,1, [{clause,7, [{var,7,'Who'}], [], [{call,8, {remote,8,{atom,8,io},{atom,8,fwrite}}, [{string,8,"hello ~p"}, {cons,8,{var,8,'Who'},{nil,8}}]}]}]}, {eof,10}]
26 / 84
![Page 27: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/27.jpg)
Setting SailTransform some parse trees!
27 / 84
![Page 28: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/28.jpg)
Hypothetical applicationWhenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETSmethod used: select / insert / update / delete.
The tracker process could then accumulate number of calls / time. You could begin to get an idea of what processes areusing this table and how often.
28 / 84
![Page 29: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/29.jpg)
Hypothetical applicationWhenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETSmethod used: select / insert / update / delete.
The tracker process could then accumulate number of calls / time. You could begin to get an idea of what processes areusing this table and how often.
ProblemFind: ets:insert(contentious_table, Objects)
29 / 84
![Page 30: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/30.jpg)
Hypothetical applicationWhenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETSmethod used: select / insert / update / delete.
The tracker process could then accumulate number of calls / time. You could begin to get an idea of what processes areusing this table and how often.
ProblemFind: ets:insert(contentious_table, Objects)
Insert: ets_collector ! {insert, self()}
30 / 84
![Page 31: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/31.jpg)
Hypothetical applicationWhenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETSmethod used: select / insert / update / delete.
The tracker process could then accumulate number of calls / time. You could begin to get an idea of what processes areusing this table and how often.
ProblemFind: ets:insert(contentious_table, Objects)
Insert: ets_collector ! {insert, self()}
Bonus: ets_collector ! {insert, length(Objects), self()}
31 / 84
![Page 32: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/32.jpg)
What does that look like in AF???
1> {ok, Tokens, _} = erl_scan:string("ets:insert(contentious_table, Objects).").
2> {ok, Forms} = erl_parse:parse_exprs(Tokens).
3> Forms.[{call,1, {remote,1,{atom,1,ets},{atom,1,insert}}, [{atom,1,contentious_table},{var,1,'Objects'}]}]
32 / 84
![Page 33: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/33.jpg)
What does that look like in AF???
1> {ok, Tokens, _} = erl_scan:string("ets:insert(contentious_table, Objects).").
2> {ok, Forms} = erl_parse:parse_exprs(Tokens).
3> Forms.[{call,1, {remote,1,{atom,1,ets},{atom,1,insert}}, [{atom,1,contentious_table},{var,1,'Objects'}]}]
OK, match on
{call, _, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, {var, _, 'Objects'}]}
33 / 84
Just make sure not to match on Objects since the variable name might be different.
![Page 34: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/34.jpg)
... and insert ...
1> {ok, Tokens, _} = erl_scan:string("ets_collector ! {insert, self()}.").
2> {ok, Forms} = erl_parse:parse_exprs(Tokens).
3> Forms.[{op,1,'!', {atom,1,ets_collector}, {tuple,1,[{atom,1,insert},{call,1,{atom,1,self},[]}]}}]
34 / 84
![Page 35: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/35.jpg)
Transform function!transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, Objects]} = Form) -> {op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}};transform_ets_insert(Form) -> Form.
35 / 84
![Page 36: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/36.jpg)
Transform function!transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, Objects]} = Form) -> {op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}};transform_ets_insert(Form) -> Form.
... well, almost ...
36 / 84
![Page 37: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/37.jpg)
Turn this
ets:insert(contentious_table, Objects),
37 / 84
![Page 38: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/38.jpg)
Turn this
ets:insert(contentious_table, Objects),
Into this
ets_collector ! {insert, self()},ets:insert(contentious_table, Objects),
without changing the shape of the parse tree.
replace a single node with a different single node (not a list)
38 / 84
![Page 39: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/39.jpg)
What about this?
begin ets_collector ! {insert, self()}, ets:insert(contentious_table, Objects)end,
39 / 84
![Page 40: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/40.jpg)
What about this?
begin ets_collector ! {insert, self()}, ets:insert(contentious_table, Objects)end,
✔Single AST node
40 / 84
![Page 41: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/41.jpg)
What about this?
begin ets_collector ! {insert, self()}, ets:insert(contentious_table, Objects)end,
✔Single AST node
✔Same expression value
41 / 84
![Page 42: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/42.jpg)
Complete AST node transform
transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, Objects]} = Form) -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}}, Form]};transform_ets_insert(Form) -> Form.
42 / 84
![Page 43: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/43.jpg)
Complete AST node transform
transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, Objects]} = Form) -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}}, Form]};transform_ets_insert(Form) -> Form.
Now to use it!
43 / 84
![Page 44: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/44.jpg)
Transform thischange_username(UserId, UserName) when UserId =:= 0 -> error("Can't change admin user name");change_username(UserId, UserName) -> Users = ets:lookup(contentious_table, UserId), [User] = Users, case User#user.group of luser -> error("Insufficient privileges"); G when G =:= user; G =:= admin -> ets:insert(contentious_table, User#user{name = UserName}) end.
44 / 84
![Page 45: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/45.jpg)
{function,25,change_username,2, [{clause,25, [{var,25,'UserId'},{var,25,'UserName'}], [[{op,25,'=:=',{var,25,'UserId'},{integer,25,0}}]], [{call,26, {atom,26,error}, [{string,26,"Can't change admin user name"}]}]}, {clause,27, [{var,27,'UserId'},{var,27,'UserName'}], [], [{match,28, {var,28,'Users'}, {call,28, {remote,28,{atom,28,ets},{atom,28,lookup}}, [{atom,28,contentious_table},{var,28,'UserId'}]}}, {match,29,{cons,29,{var,29,'User'},{nil,29}},{var,29,'Users'}}, {case,30, {record_field,30,{var,30,'User'},user,{atom,30,group}}, [{clause,31, [{atom,31,luser}], [], [{call,32, {atom,32,error}, [{string,32,"Insufficient privileges"}]}]}, {clause,33, [{var,33,'G'}], [[{op,33,'=:=',{var,33,'G'},{atom,33,user}}], [{op,33,'=:=',{var,33,'G'},{atom,33,admin}}]], [{call,34, {remote,34,{atom,34,ets},{atom,34,insert}}, [{atom,34,contentious_table}, {record,34, {var,34,'User'}, user, [{record_field,34, {atom,34,name}, {var,34,'UserName'}}]}]}]}]}]}]}
45 / 84
![Page 46: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/46.jpg)
Lets take a step back
46 / 84
![Page 47: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/47.jpg)
Working with Abstract FormatBring your sword to the dragon fight
47 / 84
![Page 48: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/48.jpg)
Isn't there something to help?
stdlibepp Erlang preprocessor (macros and includes)erl_scan Turn text into tokenserl_parse Turn tokens into an ASTerl_pp Turn an AST back into text (Pretty Print it)erl_eval Execute ASTserl_id_trans Identity transform that walks the whole AST
48 / 84
![Page 49: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/49.jpg)
Isn't there something to help?
stdlibepp Erlang preprocessor (macros and includes)erl_scan Turn text into tokenserl_parse Turn tokens into an ASTerl_pp Turn an AST back into text (Pretty Print it)erl_eval Execute ASTserl_id_trans Identity transform that walks the whole AST
syntax_toolserl_prettypr Another prettyprinter of ASTserl_syntax Define a 'superset' of the stdlib ASTerl_syntax_lib Helper functions for working with ASTs
49 / 84
![Page 50: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/50.jpg)
Common pattern1. Find an AST node of interest, e.g., a function call
2. Extract context / detail
3. Create a modified node
4. Replace the node with the modified one
5. Do this for all nodes
6. Hand the new AST back to the compiler
50 / 84
![Page 51: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/51.jpg)
erl_syntax_lib
map(Fun, AST) -> AST1.
map_fun(AstNode) -> AstNode1.
51 / 84
![Page 52: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/52.jpg)
erl_syntax_lib
map(Fun, AST) -> AST1.
map_fun(AstNode) -> AstNode1.
fold(Fun, Acc, AST) -> Acc1.
fold_fun(AstNode, Acc) -> Acc1.
52 / 84
![Page 53: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/53.jpg)
erl_syntax_lib
map(Fun, AST) -> AST1.
map_fun(AstNode) -> AstNode1.
fold(Fun, Acc, AST) -> Acc1.
fold_fun(AstNode, Acc) -> Acc1.
mapfold(Fun, Acc, AST) -> {AST1, Acc1}.
mapfold_fun(Node, Acc) -> {Node1, Acc1}.
53 / 84
![Page 54: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/54.jpg)
Complete parse transform
parse_transform(Forms, _Options) -> Forms1 = [erl_syntax_lib:map( fun(Node) -> transform_ets_insert( erl_syntax:revert(Node)) end, F) || F <- Forms], erl_syntax:revert_forms(Forms1).
transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, _Objects]} = Form) -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}}, Form]};transform_ets_insert(Form) -> Form.
54 / 84
![Page 55: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/55.jpg)
A module is a list of trees (not a tree of trees)
parse_transform(Forms, _Options) -> Forms1 = [erl_syntax_lib:map( fun(Node) -> transform_ets_insert( erl_syntax:revert(Node)) end, F) || F <- Forms], erl_syntax:revert_forms(Forms1).
transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, _Objects]} = Form) -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}}, Form]};transform_ets_insert(Form) -> Form.
55 / 84
![Page 56: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/56.jpg)
erl_syntax_lib has a different AST
parse_transform(Forms, _Options) -> Forms1 = [erl_syntax_lib:map( fun(Node) -> transform_ets_insert( erl_syntax:revert(Node)) end, F) || F <- Forms], erl_syntax:revert_forms(Forms1).
transform_ets_insert({call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, _Objects]} = Form) -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line,{atom,Line,self},[]}]}}, Form]};transform_ets_insert(Form) -> Form.
56 / 84
![Page 57: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/57.jpg)
Why not parse transforms?
57 / 84
![Page 58: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/58.jpg)
Why not parse transforms?Quite complex requires a deep understanding of the Erlang grammar
58 / 84
![Page 59: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/59.jpg)
Why not parse transforms?Quite complex requires a deep understanding of the Erlang grammar
Abstract Format can change as the language evolves
59 / 84
![Page 60: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/60.jpg)
Why not parse transforms?Quite complex requires a deep understanding of the Erlang grammar
Abstract Format can change as the language evolves
Your bug just became a compiler bug
60 / 84
![Page 61: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/61.jpg)
Why not parse transforms?Quite complex requires a deep understanding of the Erlang grammar
Abstract Format can change as the language evolves
Your bug just became a compiler bug
Slows down compilation
61 / 84
![Page 62: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/62.jpg)
Why not parse transforms?Quite complex requires a deep understanding of the Erlang grammar
Abstract Format can change as the language evolves
Your bug just became a compiler bug
Slows down compilation
Code becomes difficult or impossible to reason about
62 / 84
![Page 63: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/63.jpg)
Parse transforms in the wild
63 / 84
![Page 64: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/64.jpg)
Another Erlang to Object Notation translator*(aeon) https://github.com/garretsmith/aeon
-record(user, { name :: binary(), height :: float(), birthday :: {Year :: integer(), Month :: integer(), Day :: integer()}, privileges :: [privilege()] }).
User = #user{ name = <<"Garret Smith">>, height = 6.0, birthday = {1982, 06, 29}, privileges = [login, create, delete, grant] },Json = jsx:encode(aeon:record_to_jsx(User, ?MODULE)),User1 = aeon:to_record(jsx:decode(Json), ?MODULE, user),User = User1
{ "name":"Garret Smith", "height":6.0, "birthday":[1982,6,29], "privileges":["login","create","delete","grant"]}
*I wrote it
64 / 84
![Page 65: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/65.jpg)
aeon Parse Transform
-include_lib("parse_trans/include/codegen.hrl").
parse_transform(Forms, Options) -> parse_trans:top(fun do_transform/2, Forms, Options).
do_transform(Forms, Context) -> F = erl_syntax_lib:analyze_forms(Forms), case lists:keyfind(attributes, 1, F) of false -> Forms; {K, R} -> Attr = lists:flatten([transform_attribute(A) || A<-R]), Func = codegen:gen_function( ?FUN_NAME, fun() -> {'$var', Attr} end), Forms2 = parse_trans:do_insert_forms(below, [Func], Forms, Context), Forms3 = parse_trans:export_function(?FUN_NAME, 0, Forms2), parse_trans:revert(Forms3) end.
65 / 84
![Page 66: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/66.jpg)
parse_transhttps://github.com/uwiger/parse_trans.git
Convenience functions for common cases.
Error handling for your transform (you will want this)
codegen: A parse transform for your parse transform.
Create new functions or entire modules from thin air.
66 / 84
![Page 67: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/67.jpg)
parse_transhttps://github.com/uwiger/parse_trans.git
Convenience functions for common cases.
Error handling for your transform (you will want this)
codegen: A parse transform for your parse transform.
Create new functions or entire modules from thin air.
exprecs, generate and export accessor functions for record fields.
67 / 84
![Page 68: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/68.jpg)
lager (as in beer)https://github.com/basho/lager.git
Turn the log statement lager:info("~s", ["hello"]) into:
case {whereis(lager_event), whereis(lager_event), lager_config:get({lager_event, loglevel}, {0, []})} of {undefined, undefined, _} -> fun () -> {error, lager_not_running} end(); {undefined, _, _} -> fun () -> {error, {sink_not_configured, lager_event}} end(); {__Pidlager_test6, _, {__Levellager_test6, __Traceslager_test6}} when __Levellager_test6 band 64 /= 0 orelse __Traceslager_test6 /= [] -> lager:do_log(info, [{module, lager_test}, {function, say_hello}, {line, 6}, {pid, pid_to_list(self())}, {node, node()} | lager:md()], "~s", ["hello"], 4096, 64, __Levellager_test6, __Traceslager_test6, lager_event, __Pidlager_test6); _ -> okend
68 / 84
![Page 69: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/69.jpg)
PARE - PARallel Execution in Erlanghttp://chlorophil.blogspot.com/2007/11/pareparallelexecutioninerlang.html
Basic idea: embed atoms to automatically parallelize execution of sequential code.
parallel_next_3,A = a(),b(),c(),
69 / 84
![Page 70: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/70.jpg)
seqbindhttps://github.com/spawngrid/seqbind
V1 = foo(V),V2 = bar(V1),V3 = baz(V2)
V@ = foo(V),V@ = bar(V@),V@ = baz(V@)
70 / 84
![Page 71: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/71.jpg)
Zen of parse transforms
71 / 84
![Page 72: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/72.jpg)
Zen of parse transformsraw speed, where the time invested in optimization pays off because of widespread reuse (lager).
72 / 84
![Page 73: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/73.jpg)
Zen of parse transformsraw speed, where the time invested in optimization pays off because of widespread reuse (lager).
Repetitive code generation, e.g. record access functions (exprecs).
73 / 84
![Page 74: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/74.jpg)
Zen of parse transformsraw speed, where the time invested in optimization pays off because of widespread reuse (lager).
Repetitive code generation, e.g. record access functions (exprecs).
Make use of information lost during compilation, like types (aeon).
74 / 84
![Page 75: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/75.jpg)
Zen of parse transformsraw speed, where the time invested in optimization pays off because of widespread reuse (lager).
Repetitive code generation, e.g. record access functions (exprecs).
Make use of information lost during compilation, like types (aeon).
Extend Erlang with new, custom semanics (seqbind).
75 / 84
![Page 76: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/76.jpg)
Zen of parse transformsraw speed, where the time invested in optimization pays off because of widespread reuse (lager).
Repetitive code generation, e.g. record access functions (exprecs).
Make use of information lost during compilation, like types (aeon).
Extend Erlang with new, custom semanics (seqbind).
Experimentation with new language semantics. Easier than writing a compiler (PARE).
76 / 84
![Page 77: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/77.jpg)
Zen of parse transformsraw speed, where the time invested in optimization pays off because of widespread reuse (lager).
Repetitive code generation, e.g. record access functions (exprecs).
Make use of information lost during compilation, like types (aeon).
Extend Erlang with new, custom semanics (seqbind).
Experimentation with new language semantics. Easier than writing a compiler (PARE).
Metaprogramming is it's own reward (inline transform)!
77 / 84
![Page 78: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/78.jpg)
A parse transform enabling inline module transforms!
parse_transform(Forms, Options) -> {[InlineTransform], RemainingForms} = lists:partition( fun({function, _, inline_transform, 2, _}) -> true; (_) -> false end, Forms), TransformerExpressions = extract_exprs(InlineTransform),
{value, Transformed, _Vars} = erl_eval:exprs(TransformerExpressions, orddict:from_list([{'Forms', RemainingForms}, {'Options', Options}])), erl_syntax:revert_forms(Transformed).
extract_exprs({function, _Line, _Name, _Arity, Clauses}) -> {clause, _, _Args, _When, Exprs} = hd(Clauses), Exprs.
78 / 84
![Page 79: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/79.jpg)
pull the 'inline_transform' function out of the AST
parse_transform(Forms, Options) -> {[InlineTransform], RemainingForms} = lists:partition( fun({function, _, inline_transform, 2, _}) -> true; (_) -> false end, Forms), TransformerExpressions = extract_exprs(InlineTransform),
{value, Transformed, _Vars} = erl_eval:exprs(TransformerExpressions, orddict:from_list([{'Forms', RemainingForms}, {'Options', Options}])), erl_syntax:revert_forms(Transformed).
extract_exprs({function, _Line, _Name, _Arity, Clauses}) -> {clause, _, _Args, _When, Exprs} = hd(Clauses), Exprs.
79 / 84
![Page 80: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/80.jpg)
Extract the body of the transform
parse_transform(Forms, Options) -> {[InlineTransform], RemainingForms} = lists:partition( fun({function, _, inline_transform, 2, _}) -> true; (_) -> false end, Forms), TransformerExpressions = extract_exprs(InlineTransform),
{value, Transformed, _Vars} = erl_eval:exprs(TransformerExpressions, orddict:from_list([{'Forms', RemainingForms}, {'Options', Options}])), erl_syntax:revert_forms(Transformed).
extract_exprs({function, _Line, _Name, _Arity, Clauses}) -> {clause, _, _Args, _When, Exprs} = hd(Clauses), Exprs.
80 / 84
![Page 81: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/81.jpg)
eval the body against the remaining AST Forms
parse_transform(Forms, Options) -> {[InlineTransform], RemainingForms} = lists:partition( fun({function, _, inline_transform, 2, _}) -> true; (_) -> false end, Forms), TransformerExpressions = extract_exprs(InlineTransform),
{value, Transformed, _Vars} = erl_eval:exprs(TransformerExpressions, orddict:from_list([{'Forms', RemainingForms}, {'Options', Options}])), erl_syntax:revert_forms(Transformed).
extract_exprs({function, _Line, _Name, _Arity, Clauses}) -> {clause, _, _Args, _When, Exprs} = hd(Clauses), Exprs.
81 / 84
![Page 82: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/82.jpg)
ETS collector as inline transform
inline_transform(Forms, Options) -> [erl_syntax_lib:map( fun(Node) -> case erl_syntax:revert(Node) of {call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, _Objects]} = Form -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line, {atom,Line,self},[]}]}}, Form]}; Form -> Form end end, F) || F <- Forms].
82 / 84
![Page 83: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/83.jpg)
All inline - no sub-functions
inline_transform(Forms, Options) -> [erl_syntax_lib:map( fun(Node) -> case erl_syntax:revert(Node) of {call, Line, {remote, _, {atom, _, ets}, {atom, _, insert}}, [{atom, _, contentious_table}, _Objects]} = Form -> {block, Line, [{op,Line,'!', {atom,Line,ets_collector}, {tuple,Line,[{atom,Line,insert}, {call,Line, {atom,Line,self},[]}]}}, Form]}; Form -> Form end end, F) || F <- Forms].
83 / 84
![Page 84: HERE BE DRAGONS - Erlang · PDF fileHypothetical application Whenever the ETS table contentious_table is accessed, fire off a message to a tracker process with the ETS](https://reader033.fdocuments.us/reader033/viewer/2022051600/5a9e44077f8b9a2e688cbd91/html5/thumbnails/84.jpg)
Thanks
84 / 84