上回书,我们说到飞天玉虎蒋伯芳来到蜈蚣岭,不是,重来,上回咱们说到可以在Erlang Shell里面手工构造,加载并调用一个模块.在那个demo里面,我把多个Form单独生成出来,最后放在一起做compile:forms,是不是可以简单点?我们先看完整的module代码,erl_scan:string之后是什么样子的:

erl_syntax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Eshell V5.10.2  (abort with ^G)
1> Code = "-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". ".
"-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". "
2> {ok,Tokens,_} =erl_scan:string(Code).
{ok,[{'-',1},
     {atom,1,module},
     {'(',1},
     {atom,1,t},
     {')',1},
     {dot,1},
     {'-',2},
     {atom,2,export},
     {'(',2},
     {'[',2},
     {atom,2,say},
     {'/',2},
     {integer,2,0},
     {']',2},
     {')',2},
     {dot,2},
     {atom,4,say},
     {'(',4},
     {')',4},
     {'->',4},
     {string,4,"Hello world!!"},
     {dot,4}],
    4}

  

可以看到上面的list里面包含了若干Form,erl_scan可以逐行解析代码:
1
2
3
4
5
6
7
8
9
4> erl_scan:tokens([],Code,1).
{done,{ok,[{'-',1},
           {atom,1,module},
           {'(',1},
           {atom,1,t},
           {')',1},
           {dot,1}],
          2},
      "-export([say/0]).\n\nsay() -> \"Hello world!!\". "}

  

当然还有更简单的方式,dynamic_compile 项目把这些事情都做了,还考虑了更为复杂的情况,比如头文件,宏,注释,record之类的, https://github.com/JacobVorreuter/dynamic_compile/blob/master/src/dynamic_compile.erl 下面就是dynamic_compile使用的一个例子: 
1
2
3
4
5
6
7
8
Eshell V5.10.2  (abort with ^G)
1> Code = "-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". ".
"-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". "
2> dynamic_compile:load_from_string(Code).
{module,t}
3> t:say().
"Hello world!!"
4>

  

上面拼字符串的方法看起来丑?你可以选择erl_syntax,下面我们用比较"优雅"的方法去创建t模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Eshell V5.10.2  (abort with ^G)
1> M  = erl_syntax:attribute(erl_syntax:atom(module),[erl_syntax:atom(t)]).
{tree,attribute,
      {attr,0,[],none},
      {attribute,{tree,atom,{attr,0,[],none},module},
                 [{tree,atom,{attr,0,[],none},t}]}}
2> MF =  erl_syntax:revert(M).
{attribute,0,module,t}
3> E = erl_syntax:attribute(erl_syntax:atom(export),[erl_syntax:list([erl_syntax:arity_qualifier(erl_syntax:atom(say),erl_syntax:integer(0))])]).
{tree,attribute,
    {attr,0,[],none},
    {attribute,
        {tree,atom,{attr,0,[],none},export},
        [{tree,list,
             {attr,0,[],none},
             {list,
                 [{tree,arity_qualifier,
                      {attr,0,[],none},
                      {arity_qualifier,
                          {tree,atom,{attr,0,[],none},say},
                          {tree,integer,{attr,0,[],none},0}}}],
                 none}}]}}
4> ExportForm = erl_syntax:revert(E).
{attribute,0,export,[{say,0}]}
5>
5>
5> Clause= erl_syntax:clause([],[],[erl_syntax:atom(hello_world)]).
{tree,clause,
      {attr,0,[],none},
      {clause,[],none,[{tree,atom,{attr,0,[],none},hello_world}]}}
6>
6> Function =  erl_syntax:function(erl_syntax:atom(say),[Clause]).
{tree,function,
      {attr,0,[],none},
      {func,{tree,atom,{attr,0,[],none},say},
            [{tree,clause,
                   {attr,0,[],none},
                   {clause,[],none,
                           [{tree,atom,{attr,0,[],none},hello_world}]}}]}}
7> FunctionForm = erl_syntax:revert(Function).
{function,0,say,0,[{clause,0,[],[],[{atom,0,hello_world}]}]}
8>  {ok, Mod, Bin1} = compile:forms([MF,ExportForm, FunctionForm]).
{ok,t,
    <<70,79,82,49,0,0,1,208,66,69,65,77,65,116,111,109,0,0,0,
      57,0,0,0,6,1,116,...>>}
9> t:say().
** exception error: undefined function t:say/0
10> code:load_binary(Mod, [], Bin1).
{module,t}
11> t:say().
hello_world
12>

  

Erlang Shared Data using mochiglobal 里面mochiglobal 就是用这种方法实现的,不过,不过,又会有人提意见了,这编写难度也太大了,能折中一下吗?好吧,请出下一位嘉宾smerl
我曾经介绍过开源项目smerl,其定位就是Simple Metaprogramming for Erlang, 我们可以从这份代码里面学到erl_scan erl_parse erl_eval更灵活的应用,项目地址:http://code.google.com/p/smerl/ 
1
2
3
4
5
6
7
test_smerl() ->
      M1 = smerl:new(foo),
      {ok, M2} = smerl:add_func(M1, "bar() -> 1 + 1."),
      smerl:compile(M2),
      foo:bar(),   % returns 2``
      smerl:has_func(M2, bar, 0). % returns true

  

parse_transform

在上篇文章里面,我需要反复生成 Abstract Format,开始手工搞了一下,后来不胜其烦就使用了一下parse_transform.这东西是干什么用的呢?
{parse_transform,Module}
Causes the parse transformation function Module:parse_transform/2 to be applied to the parsed code before the code is checked for errors.
对,它就是允许你在检查错误之前插入自己的逻辑,把那些"奇怪的东西"变成正常的东西,当然你可以选择什么都不做,仅仅打印,看代码:
1
2
3
4
5
6
-module(print_form).
-export([parse_transform/2]).
parse_transform(Forms, _Options) ->
  io:format("forms: ~p~n", [Forms]),
  Forms.

  

下面,我们写一个简单的模块a.erl,然后编译它,看输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@nimbus demo]# cat a.erl
-module(a).
-compile({parse_transform,print_form}).
-export([test/0]).
  
test()->
  "hello world!".
[root@nimbus demo]# erlc -o . -pa . a.erl 
forms: [{attribute,1,file,{"a.erl",1}},
        {attribute,1,module,a},
        {attribute,3,export,[{test,0}]},
        {function,5,test,0,[{clause,5,[],[],[{string,6,"hello world!"}]}]},
        {eof,10}]

  

好吧,感冒,鼻子堵得难受,先到这里吧
参考资料:
[0] erl_syntax  http://erlang.org/doc/man/erl_syntax.html
[1] Erlang: How to Create and Compile Module in Run-time
http://vas.io/blog/2013/03/23/erlang-how-to-create-and-compile-module-in-run-time/
[2] Hacking-Erlang http://zh.scribd.com/doc/22451864/Hacking-Erlang
最后小图一张,最早在山东卫视凌晨剧场看过第一季,现在已经14季了, 老员工只有Nicky ,Sara ,Jim了:

上回书,我们说到飞天玉虎蒋伯芳来到蜈蚣岭,不是,重来,上回咱们说到可以在Erlang Shell里面手工构造,加载并调用一个模块.在那个demo里面,我把多个Form单独生成出来,最后放在一起做compile:forms,是不是可以简单点?我们先看完整的module代码,erl_scan:string之后是什么样子的:

erl_syntax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Eshell V5.10.2  (abort with ^G)
1> Code = "-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". ".
"-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". "
2> {ok,Tokens,_} =erl_scan:string(Code).
{ok,[{'-',1},
     {atom,1,module},
     {'(',1},
     {atom,1,t},
     {')',1},
     {dot,1},
     {'-',2},
     {atom,2,export},
     {'(',2},
     {'[',2},
     {atom,2,say},
     {'/',2},
     {integer,2,0},
     {']',2},
     {')',2},
     {dot,2},
     {atom,4,say},
     {'(',4},
     {')',4},
     {'->',4},
     {string,4,"Hello world!!"},
     {dot,4}],
    4}

  

可以看到上面的list里面包含了若干Form,erl_scan可以逐行解析代码:
1
2
3
4
5
6
7
8
9
4> erl_scan:tokens([],Code,1).
{done,{ok,[{'-',1},
           {atom,1,module},
           {'(',1},
           {atom,1,t},
           {')',1},
           {dot,1}],
          2},
      "-export([say/0]).\n\nsay() -> \"Hello world!!\". "}

  

当然还有更简单的方式,dynamic_compile 项目把这些事情都做了,还考虑了更为复杂的情况,比如头文件,宏,注释,record之类的, https://github.com/JacobVorreuter/dynamic_compile/blob/master/src/dynamic_compile.erl 下面就是dynamic_compile使用的一个例子: 
1
2
3
4
5
6
7
8
Eshell V5.10.2  (abort with ^G)
1> Code = "-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". ".
"-module(t).\n-export([say/0]).\n\nsay() -> \"Hello world!!\". "
2> dynamic_compile:load_from_string(Code).
{module,t}
3> t:say().
"Hello world!!"
4>

  

上面拼字符串的方法看起来丑?你可以选择erl_syntax,下面我们用比较"优雅"的方法去创建t模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Eshell V5.10.2  (abort with ^G)
1> M  = erl_syntax:attribute(erl_syntax:atom(module),[erl_syntax:atom(t)]).
{tree,attribute,
      {attr,0,[],none},
      {attribute,{tree,atom,{attr,0,[],none},module},
                 [{tree,atom,{attr,0,[],none},t}]}}
2> MF =  erl_syntax:revert(M).
{attribute,0,module,t}
3> E = erl_syntax:attribute(erl_syntax:atom(export),[erl_syntax:list([erl_syntax:arity_qualifier(erl_syntax:atom(say),erl_syntax:integer(0))])]).
{tree,attribute,
    {attr,0,[],none},
    {attribute,
        {tree,atom,{attr,0,[],none},export},
        [{tree,list,
             {attr,0,[],none},
             {list,
                 [{tree,arity_qualifier,
                      {attr,0,[],none},
                      {arity_qualifier,
                          {tree,atom,{attr,0,[],none},say},
                          {tree,integer,{attr,0,[],none},0}}}],
                 none}}]}}
4> ExportForm = erl_syntax:revert(E).
{attribute,0,export,[{say,0}]}
5>
5>
5> Clause= erl_syntax:clause([],[],[erl_syntax:atom(hello_world)]).
{tree,clause,
      {attr,0,[],none},
      {clause,[],none,[{tree,atom,{attr,0,[],none},hello_world}]}}
6>
6> Function =  erl_syntax:function(erl_syntax:atom(say),[Clause]).
{tree,function,
      {attr,0,[],none},
      {func,{tree,atom,{attr,0,[],none},say},
            [{tree,clause,
                   {attr,0,[],none},
                   {clause,[],none,
                           [{tree,atom,{attr,0,[],none},hello_world}]}}]}}
7> FunctionForm = erl_syntax:revert(Function).
{function,0,say,0,[{clause,0,[],[],[{atom,0,hello_world}]}]}
8>  {ok, Mod, Bin1} = compile:forms([MF,ExportForm, FunctionForm]).
{ok,t,
    <<70,79,82,49,0,0,1,208,66,69,65,77,65,116,111,109,0,0,0,
      57,0,0,0,6,1,116,...>>}
9> t:say().
** exception error: undefined function t:say/0
10> code:load_binary(Mod, [], Bin1).
{module,t}
11> t:say().
hello_world
12>

  

Erlang Shared Data using mochiglobal 里面mochiglobal 就是用这种方法实现的,不过,不过,又会有人提意见了,这编写难度也太大了,能折中一下吗?好吧,请出下一位嘉宾smerl
我曾经介绍过开源项目smerl,其定位就是Simple Metaprogramming for Erlang, 我们可以从这份代码里面学到erl_scan erl_parse erl_eval更灵活的应用,项目地址:http://code.google.com/p/smerl/ 
1
2
3
4
5
6
7
test_smerl() ->
      M1 = smerl:new(foo),
      {ok, M2} = smerl:add_func(M1, "bar() -> 1 + 1."),
      smerl:compile(M2),
      foo:bar(),   % returns 2``
      smerl:has_func(M2, bar, 0). % returns true

  

parse_transform

在上篇文章里面,我需要反复生成 Abstract Format,开始手工搞了一下,后来不胜其烦就使用了一下parse_transform.这东西是干什么用的呢?
{parse_transform,Module}
Causes the parse transformation function Module:parse_transform/2 to be applied to the parsed code before the code is checked for errors.
对,它就是允许你在检查错误之前插入自己的逻辑,把那些"奇怪的东西"变成正常的东西,当然你可以选择什么都不做,仅仅打印,看代码:
1
2
3
4
5
6
-module(print_form).
-export([parse_transform/2]).
parse_transform(Forms, _Options) ->
  io:format("forms: ~p~n", [Forms]),
  Forms.

  

下面,我们写一个简单的模块a.erl,然后编译它,看输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@nimbus demo]# cat a.erl
-module(a).
-compile({parse_transform,print_form}).
-export([test/0]).
  
test()->
  "hello world!".
[root@nimbus demo]# erlc -o . -pa . a.erl 
forms: [{attribute,1,file,{"a.erl",1}},
        {attribute,1,module,a},
        {attribute,3,export,[{test,0}]},
        {function,5,test,0,[{clause,5,[],[],[{string,6,"hello world!"}]}]},
        {eof,10}]

  

好吧,感冒,鼻子堵得难受,先到这里吧
参考资料:
[0] erl_syntax  http://erlang.org/doc/man/erl_syntax.html
[1] Erlang: How to Create and Compile Module in Run-time
http://vas.io/blog/2013/03/23/erlang-how-to-create-and-compile-module-in-run-time/
[2] Hacking-Erlang http://zh.scribd.com/doc/22451864/Hacking-Erlang
最后小图一张,最早在山东卫视凌晨剧场看过第一季,现在已经14季了, 老员工只有Nicky ,Sara ,Jim了:

[Erlang 0111] Erlang Abstract Format , Part 2相关推荐

  1. [Erlang 0034] Erlang iolist

    问题的缘起是芒果在使用mochiweb的过程中遇到一个异常,在google的讨论组中我找到了同样的问题: =ERROR REPORT==== 7-Apr-2011::18:58:22 === &quo ...

  2. [Erlang危机]Erlang In Danger 序言(必读)

    原创文章,转载请注明出处:服务器非业余研究http://blog.csdn.net/erlib 作者Sunface 联系邮箱:cto@188.com 这本新书是Learn You Some Erlan ...

  3. [Erlang 0057] Erlang 排错利器: Erlang Crash Dump Viewer

    Erlang Crash Dump Viewer真的是排错的天兵神器,还记得我们之前曾经讨论过[Erlang 0013]抓取Erlang进程运行时信息 [Erlang 0012]Erlang Proc ...

  4. [Erlang 0014]Erlang垃圾回收机制

    前面的Erlang杂记中我们简单提到过Erlang的垃圾回收机制:1.以进程为单位进行垃圾回收 2.ETS和原子不参与垃圾回收.今天我们继续这一话题,关注更多关于细节. 在Erlang的官方文档中,关 ...

  5. 解析Erlang日志组件lager的lager_transform模块

    为什么80%的码农都做不了架构师?>>>    使用 lager 的时候,在编译应用的时候,需要加入选项 {parse_transform, lager_transform} erl ...

  6. [Erlang 0079] RabbitMQ 初探

    最近在项目中实践RabbitMQ,比较幸运现在除了官方网站,还有一本非常棒的书可以读:RabbitMQ in Action;这本书目前还没有中文版或者影印版,但是从网上很容易找到PDF版本和epub ...

  7. 30 分钟学 Erlang

    30 分钟学 Erlang (一) Shawn_xiaoyu https://www.jianshu.com/p/b45eb9314d1e 本文写给谁看的? 那些已经有过至少一门编程语言基础,并且需要 ...

  8. ERLANG日期与时间

    在开发过程中,有两个概念是和地区区域相关的:字符编码和时间;编码和时间的规范演变过程中有文化的冲突有历史的遗留,是软件开发中充满人文气息的一角;关于字符编码我之前整理过一篇文章, [Erlang 00 ...

  9. Erlang安装 /开启关闭 /配置开发环境 /运行程序

    目录: 1. Erlang安装 2. 开启和停止Erlang shell 3. 配置开发环境 4. 运行程序的几种方法 1. Erlang安装 (1). 二进制发布版(此处不做介绍) (2). 从源代 ...

最新文章

  1. 解决 apache 2.4.1 无法解析shtml中的expr指令问题
  2. Xamarin.FormsShell基础教程(8)Shell的模版构成
  3. my ax 4 faq
  4. 河海大学物联网计算机考研,河海大学:物联网工程学院2020年硕士研究生建议录取名单出炉...
  5. JavaScript中的继承
  6. python嵌套字典代码_python – 尝试在嵌套字典中查找唯一值的总和. (见例子!)
  7. 高清精美壁纸:2013年9月桌面日历壁纸免费下载
  8. 【UCHome二次开发】全局变量
  9. component是什么接口_逐行解读Spring(二)什么,自定义标签没听说过?
  10. 年前最后一期!知识图谱理论与实战(线下集训)
  11. 金古桥机器人_泽塔奥特曼上演“吃瘪预定”,金古桥强势回顾,阿尔法被骑着打脸...
  12. MATLAB编程思想
  13. 西安力邦智能医疗amp;可穿戴设备沙龙--第1期---苹果HealthKit、谷歌GoogleFit来袭,智能医疗要爆发吗?...
  14. Anroid camera + mediacodec
  15. WinRM 如何设置 TrustedHosts
  16. 营销传播“四个时代”与“八大理论”
  17. 新南威尔士 计算机硕士,新南威尔士大学计算机硕士申请条件及案例
  18. 用MySQL绘制新年祝福图形_2020年春节,你有哪些与众不同的祝福语?
  19. 修改MP4文件二进制内容,实现安卓Camera2旋转录制视频画面功能
  20. inductive bias:归纳偏置

热门文章

  1. 网站建设服务器拼租服务器好还是独立服务器好
  2. 中国中学生击剑锦标赛
  3. 一川烟草,满城飞絮,梅子黄时雨
  4. “中国无人车第一案”出现神转折:景驰为何“投诚”百度?
  5. 新人转行IC该怎么选择岗位?(内附各岗位学习视频)
  6. 30条爆笑的程序员梗PHP是最好的语言
  7. golang并发编程之Ticker
  8. 自定义Launcher桌面图标无法加载的问题
  9. Jetson Nano安装ROS错误合集
  10. Python中 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape错误解决方法