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

erl_syntax

 
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可以逐行解析代码:
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使用的一个例子: 
 
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模块:

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/ 
 
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.
 
 对,它就是允许你在检查错误之前插入自己的逻辑,把那些"奇怪的东西"变成正常的东西,当然你可以选择什么都不做,仅仅打印,看代码:
 
-module(print_form).
-export([parse_transform/2]). parse_transform(Forms, _Options) ->
io:format("forms: ~p~n", [Forms]),
Forms.

  

 
下面,我们写一个简单的模块a.erl,然后编译它,看输出:
 
[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}]

  

好吧,感冒,鼻子堵得难受,先到这里吧
 
 
 
参考资料:
 
 
[1] Erlang: How to Create and Compile Module in Run-time
 
 
 
最后小图一张,最早在山东卫视凌晨剧场看过第一季,现在已经14季了, 老员工只有Nicky ,Sara ,Jim了:
 
 

[Erlang 0111] Erlang Abstract Format , Part 2的更多相关文章

  1. [Erlang 0110] Erlang Abstract Format , Part 1

    Erlang Abstract Format并不难懂,只是枯燥一点罢了,如果把Abstract Format的文档翻译出来,其实就是Erlang教科书中语法入门的部分. Erlang Abstract ...

  2. [Erlang 0129] Erlang 杂记 VI

    把之前阅读资料的时候记下的东西,整理了一下. Adding special-purpose processor support to the Erlang VM   P23 简单介绍了Erlang C ...

  3. [Erlang 0124] Erlang Unicode 两三事 - 补遗

    最近看了Erlang User Conference 2013上patrik分享的BRING UNICODE TO ERLANG!视频,这个分享很好的梳理了Erlang Unicode相关的问题,基本 ...

  4. [Erlang 0105] Erlang Resources 小站 2013年1月~6月资讯合集

    很多事情要做,一件一件来; Erlang Resources 小站 2013年1月~6月资讯合集,方便检索.      小站地址: http://site.douban.com/204209/     ...

  5. [Erlang 0122] Erlang Resources 2014年1月~6月资讯合集

    虽然忙,有些事还是要抽时间做; Erlang Resources 小站 2014年1月~6月资讯合集,方便检索.      小站地址: http://site.douban.com/204209/   ...

  6. Erlang 103 Erlang分布式编程

    Outline 笔记系列 Erlang环境和顺序编程Erlang并发编程Erlang分布式编程YawsErlang/OTP 日期              变更说明 2014-11-23 A Outl ...

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

    http://www.cnblogs.com/me-sa/archive/2012/04/28/2475556.html Erlang Crash Dump Viewer真的是排错的天兵神器,还记得我 ...

  8. [Erlang 0118] Erlang 杂记 V

       我在知乎回答问题不多,这个问题: "对你职业生涯帮助最大的习惯是什么?它是如何帮助你的?",我还是主动回答了一下.    做笔记 一开始笔记软件做的不好的时候就发邮件给自己, ...

  9. [Erlang 0107] Erlang实现文本截断

       抽时间处理一下之前积压的一些笔记.前段时间有网友 @稻草人 问字符串截断的问题"各位大侠 erlang截取字符串一般用哪个函数啊",有人支招用string:substr/3, ...

随机推荐

  1. 转职成为TypeScript程序员的参考手册

    写在前面 作者并没有任何可以作为背书的履历来证明自己写作这份手册的分量. 其内容大都来自于TypeScript官方资料或者搜索引擎获得,期间掺杂少量作者的私见,并会标明. 大部分内容来自于http:/ ...

  2. Egret3D研究报告(二)从Unity3D导出场景到Egret3D

    Egret3D暂时没有场编的计划,但是我们知道unity3D是一个很好的场编. 有一些游戏即使不是使用Unity3D开发,也使用Unity3D做场编.这里就不点名了,而且并不在少数. 我们就这么干. ...

  3. UniversalImageLoader的一个小问题

    最近在使用UniversalImageLoader时遇到了一个小问题,多个地方同时通过ImageLoader.getInstance().loadImage(url, new ImageSize(dp ...

  4. ABP源码分析十二:本地化

    本文逐个分析ABP中涉及到locaization的接口和类,以及相互之间的关系.本地化主要涉及两个方面:一个是语言(Language)的管理,这部分相对简单.另一个是语言对应得本地化资源(Locali ...

  5. 设计模式之接口隔离原则(ISP)

    一.定义: ISP:Interface Segregation Principle 接口隔离原则表明客户端不应该被强迫实现一些他们不会使用的接口,应该把胖接口中的方法分组,然后用多个接口代替它,每个接 ...

  6. 浏览器HTTP缓存原理分析

    以前项目中遇到了很多浏览器缓存相关的问题,也在网上查过资料,搞过服务器的配置,来确保客户端加载服务器资源的速度和资源有效性.最近仔细看了下http协议中和缓存相关的一些属性,总结一下. 浏览器缓存原理 ...

  7. windows 环境下nginx + tomcat群 + redis 实现session共享

    nginx作为负载均衡根据定义将不同的用户请求分发到不同的服务器,同时也解决了因单点部署服务器故障导致的整个应用不能访问的问题 在加入nginx之后,如果多个服务器中的一个或多个(不是全部)发生故障, ...

  8. react+redux教程(八)连接数据库的redux程序

    前面所有的教程都是解读官方的示例代码,是时候我们自己写个连接数据库的redux程序了! 例子 这个例子代码,是我自己写的程序,一个非常简单的todo,但是包含了redux插件的用法,中间件的用法,连接 ...

  9. CRL快速开发框架系列教程一(Code First数据表不需再关心)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  10. JS组件系列——Bootstrap文件上传组件:bootstrap fileinput

    前言:之前的三篇介绍了下bootstrap table的一些常见用法,发现博主对这种扁平化的风格有点着迷了.前两天做一个excel导入的功能,前端使用原始的input type='file'这种标签, ...