juggle语法规范如下:

类型:

  1. bool -> in cpp bool
  2. int -> in cpp int64
  3. float -> in cpp double
  4. string -> in cpp std::string
  5. array -> in cpp std::vector
  6. struct -> in cpp object

函数的定义则同c语言:void rpctest1(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);

整体的juggle语法如下:

  1. module juggle{
  2. void rpctest1(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);
  3.  
  4. void rpctest2(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);
  5.  
  6. }

其中module对应c++中的class,并且在服务器端会被codegen实现为一个单件,无需用户定义句柄有codegen生成对应的create代码。

codegen会依据module中函数定义,生成如下代码:

  1. #include <juggle.h>
  2.  
  3. class juggle: public module{
  4. public:
  5.   juggle() : module(ch, juggleuuid::UUID()){
  6. _service_handle->register_module_method(juggle_rpctest1,boost::bind(&juggle::call_rpctest1, this, _1));
  7. _service_handle->register_module_method(juggle_rpctest2,boost::bind(&juggle::call_rpctest2, this, _1));
  8. }
  9.  
  10. ~juggle(){
  11. }
  12. virtual void rpctest1(int64_t argv1,bool argv2,std::string argv3,double argv4,std::vector<int64_t> argv5) = 0;
  13.  
  14. void call_rpctest1(boost::shared_ptr<channel> ch, boost::shared_ptr<object> v){
  15. auto argv1 = (*v)["argv1"].asint();
  16. auto argv2 = (*v)["argv2"].asbool();
  17. auto argv3 = (*v)["argv3"].asstring();
  18. auto argv4 = (*v)["argv4"].asfloat();
  19. std::vector<int64_t> argv5;
  20. for(int i = 0; i < (*v)["argv5"].size(); i++){
  21.   v.push_back((*v)["argv5"][i].asint());
  22.      }
  23. auto ret = rpctest1(argv1, argv2, argv3, argv4, argv5);
  24. boost::shared_ptr<object> r = boost::make_shared<object>();
  25. (*r)["suuid"] = (*v)["suuid"];
  26. (*r)["method"] = (*value)["method"];
  27.  
  28. (*r)["ret"] = ret;
  29. ch->push(r);
  30. }
  31.  
  32. virtual void rpctest2(int64_t argv1,bool argv2,std::string argv3,double argv4,std::vector<int64_t> argv5) = 0;
  33.  
  34. void call_rpctest2(boost::shared_ptr<channel> ch, boost::shared_ptr<object> v){
  35. auto argv1 = (*v)["argv1"].asint();
  36. auto argv2 = (*v)["argv2"].asbool();
  37. auto argv3 = (*v)["argv3"].asstring();
  38. auto argv4 = (*v)["argv4"].asfloat();
  39. std::vector<int64_t> argv5;
  40. for(int i = 0; i < (*v)["argv5"].size(); i++){
  41. v.push_back((*v)["argv5"][i].asint());
  42. }
  43. auto ret = rpctest2(argv1, argv2, argv3, argv4, argv5);
  44. boost::shared_ptr<object> r = boost::make_shared<object>();
  45. (*r)["suuid"] = (*v)["suuid"];
  46. (*r)["method"] = (*value)["method"];
  47.  
  48. (*r)["ret"] = ret;
  49. ch->push(r);
      }
  50.  
  51. };

可以看到,codegen实现了网络层面的消息响应、协议pack/unpack以及对rpc函数的调用,返回值封包发送的代码。用户只需要继承module并实现对应的rpc函数。

其中对于obejct的定义见 https://github.com/NetEase/fossilizid/blob/master/juggle/interface/object.h

我定义了一个纯虚类,用于规范一个通信协议参数入栈和访问的接口

然后定义了一个channel https://github.com/NetEase/fossilizid/blob/master/juggle/interface/channel.h

用于规范通信的接口

对于通信而言,push/pop是非常上层的一个接口,但是这样的设计目的在于提供一个宽泛的抽象,这里通信的可以是一个消息队列,一个基于共享内存的本地跨进程通信,同样也可以是socket。

btw:另一个原因是我自己封装的网络库的长相是这样的 https://github.com/NetEase/fossilizid/tree/master/remoteq, remotoq提供的通信句柄正是channel,而提供的访问接口则是push/pop。并且通过模板参数配置了网络协议的pack/unpack。我这么实现是为了方便代码复用。

然后是对dsl语言的编译:

juggle的语法定义的关键字,除了变量类型,就只有module和struct。对于一个module的定义,在module之后是是这个module的命名,之后是'{'表示此module定义开始,至'}'表示此module定义结束。module的分析代码如下:

  1. class module(object):
  2. def __init__(self):
  3. self.keyworld = ''
  4. self.name = ''
  5. self.module = []
  6. self.machine = None
  7.  
  8. def push(self, ch):
  9. if ch == '}':
  10. self.machine = None
  11. return True
  12.  
  13. if self.machine is not None:
  14. if self.machine.push(ch):
  15. self.module.append(self.machine.func)
  16. self.machine.clear()
  17. else:
  18. if ch == '{':
  19. self.name = deleteNoneSpacelstrip(self.keyworld)
  20. self.keyworld = ''
  21. self.machine = func()
  22. return False
  23.  
  24. self.keyworld += ch
  25.  
  26. return False

在检索到'{'之后开始对module定义的分析,至'}'结束这个module的定义。

因为dsl语言本身的特性,module中只有函数定义,struct中变量定义。所以在module中,只需要分析函数定义。

self.machine = func(),对函数分析器的定义如下:

  1. class func(object):
  2. def __init__(self):
  3. self.keyworld = ''
  4. self.func = []
  5. self.argvtuple = None
  6.  
  7. def clear(self):
  8. self.keyworld = ''
  9. self.func = []
  10. self.argvtuple = None
  11.  
  12. def push(self, ch):
  13. if ch == ' ' or ch == '\0':
  14. self.keyworld = deleteNoneSpacelstrip(self.keyworld)
  15. if self.keyworld != '':
  16. if self.argvtuple is None:
  17. self.func.append(self.keyworld)
  18. else:
  19. self.argvtuple.append(self.keyworld)
  20. self.keyworld = ''
  21. return False
  22.  
  23. if ch == ',':
  24. if self.keyworld != '':
  25. self.argvtuple.append(deleteNoneSpacelstrip(self.keyworld))
  26. self.func.append(self.argvtuple)
  27. self.keyworld = ''
  28. self.argvtuple = []
  29. return False
  30.  
  31. if ch == '(':
  32. self.func.append(deleteNoneSpacelstrip(self.keyworld))
  33. self.argvtuple = []
  34. self.keyworld = ''
  35. return False
  36.  
  37. if ch == ')':
  38. if self.keyworld != '':
  39. self.argvtuple.append(deleteNoneSpacelstrip(self.keyworld))
  40. self.func.append(self.argvtuple)
  41. self.keyworld = ''
  42. return False
  43.  
  44. if ch == ';':
  45. return True
  46.  
  47. self.keyworld += ch
  48.  
  49. return False

因为无需考虑其他的语法要素的区分,函数定义的分析只需要考虑依次提取返回值类型,函数名,(,参数定义,),;函数定义结束。符号表示如下:

rettype funcname(argvlist...);

之后是对struct的分析,与module类似,在struct之后的既是struct name的定义,之后是'{'开始struct的定义,之'}'结束此struct的定义,代码如下:

  1. class struct(object):
  2. def __init__(self):
  3. self.keyworld = ''
  4. self.name = ''
  5. self.struct = []
  6. self.argvdef = []
  7.  
  8. def push(self, ch):
  9. if ch == ' ' or ch == '\0':
  10. if self.keyworld != '':
  11. self.argvdef.append(self.keyworld)
  12.  
  13. if ch == '{':
  14. self.name = deleteNoneSpacelstrip(self.keyworld)
  15. self.keyworld = ''
  16. return False
  17.  
  18. if ch == ';':
  19. self.struct.append(self.argvdef)
  20. self.argvdef = []
  21.  
  22. if ch == '}':
  23. return True
  24.  
  25. self.keyworld += ch
  26.  
  27. return False

对于struct中的变量定义,同样以'type name;'的方式直接分割。

之后是对jeggle文件的整体分析:

  1. class statemachine(object):
  2. Moduledefine = 0
  3. Funcdefine = 1
  4.  
  5. def __init__(self):
  6. self.keyworld = ''
  7. self.module = {}
  8. self.struct = {}
  9. self.machine = None
  10.  
  11. def push(self, ch):
  12. if self.machine is not None:
  13. if self.machine.push(ch):
  14. if isinstance(self.machine, module):
  15. self.module[self.machine.name] = self.machine.module
  16. self.machine = None
  17. if isinstance(self.machine, struct):
  18. self.struct[self.machine.name] = self.machine.struct
  19. self.machine = None
  20. else:
  21. self.keyworld += ch
  22.  
  23. if self.keyworld == 'module':
  24. self.machine = module()
  25. self.keyworld = ''
  26.  
  27. if self.keyworld == 'struct':
  28. self.machine = struct()
  29. self.keyworld = ''
  30.  
  31. def getmodule(self):
  32. return self.module
  33.  
  34. def getstruct(self):
  35. return self.struct
  36.  
  37. def syntaxanalysis(self, genfilestr):
  38. for str in genfilestr:
  39. for ch in str:
  40. self.push(ch)

检索到module和struct之后分别进入对应分支。

之后是codegen的代码见:

https://github.com/NetEase/fossilizid/blob/master/juggle/rpcmake/codegen.py

和之前的http://www.cnblogs.com/qianqians/p/4184441.html对比可以看到精简之后的dsl语法要方便分析许多,实作代码也要清晰不少。

和之前为c++添加rpccall的计划相比,现在的dsl语言便于提供其他语言的扩展,同时编译器也会好些很多。

btw:现在的dsl语法非常之强类型,尤其是带模板参数的array<int>,有用过protobuf和thrift的同学应该可以对比去其中的区别,希望大家能对如何设计一个好用的dsl展开讨论。

juggle dsl语法介绍及codegen浅析的更多相关文章

  1. Swift翻译之-Swift语法入门 Swift语法介绍

    目录[-] Hello world - Swift 简单赋值 控制流 函数与闭包 对象和类 枚举与结构 协议和扩展 泛型 2014.6.3日,苹果公布最新编程语言Swift,Swift是一种新的编程语 ...

  2. flex弹性布局语法介绍及使用

    一.语法介绍 Flex布局(弹性布局) ,一种新的布局解决方案 可简单.快速的实现网页布局 目前市面浏览器已全部支持1.指定容器为flex布局 display: flex; Webkit内核的浏览器, ...

  3. freemarker语法介绍及其入门教程实例

    # freemarker语法介绍及其入门教程实例 # ## FreeMarker标签使用 #####一.FreeMarker模板文件主要有4个部分组成</br>####  1.文本,直接输 ...

  4. QSS类的用法及基本语法介绍

    QSS类的用法及基本语法介绍 目录 1. 何为Qt样式表2. 样式表语法基础3. 方箱模型4. 前景与背景5. 创建可缩放样式6. 控制大小7. 处理伪状态8. 使用子部件定义微观样式8.1. 相对定 ...

  5. MD基本语法介绍

    Markdown基本语法介绍 前言 文本编辑器一般用的有富文本编辑器(也就是Word)和md了,但是wold太过于花里胡哨很多功能都用不上,所以就选择md了,简单实用,一对于我来说一般就用标题和列表就 ...

  6. react的优点:兼容了dsl语法与UI的组件化管理

    react的优点:兼容了dsl语法与UI的组件化管理. 组件化管理的dsl描述 UI: 虚拟dom:

  7. Markdown 语法介绍

    Markdown 语法介绍 from:https://coding.net/help/doc/project/markdown.html 文章内容 1 Markdown 语法介绍 1.1 标题 1.2 ...

  8. css基本概念与css核心语法介绍

    css基本概念 css是什么?不需要了解太多文字类介绍,记住css是层叠样式表,HTML是页面结构,css负责页面样式,javascrt负责静态页面的交互.CSS 能够对网页中元素位置的排版进行像素级 ...

  9. c基本语法介绍

    c语言基本语法介绍 1.把常量定义为大写字母形式,是一个很好的编程实践.

随机推荐

  1. 区块链入门(1):搭建(Ubuntu系统)Truffle v3.2.1 开发和测试环境

    本文主要讲解ubuntu 16.04下, truffle开发测试环境的搭建.  第一步:安装nodejs 和 npm,有两种比较常见的方法. 方法1:直接在nodejs官网下载nodejs-v6.10 ...

  2. 连锁反应confirm

    <script> function del(){ var flag = confirm("你真要删除么?"); if( flag ){ alert("我已被你 ...

  3. yaf学习之——yaf安装

    yaf的github源码地址 https://github.com/laruence/yaf 第一步: 下载dll扩展: http://pecl.php.net/package/yaf/2.3.5/w ...

  4. 关于struts2 Could not find action or result错误

    今天来配置这个S2SH框架的的时候,刚把环境搭建好,启动时并没有报错,但是当我写了一个action,我也准备通过这个action来访问页面,但是这里我访问的时候却给我报Could not find a ...

  5. vim 和grep 正则表达式相似和区别

    正则表达式由两种基本字符类型组成:原义(正常)文本字符和元字符.元字符使正则表达式具有处理能力.所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符 ...

  6. @Autowired标签与 @Resource标签 的区别

    Spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解,如:@Resource. @PostConstruct及@PreDestroy. 1. @Autowi ...

  7. VR全景:电商巨头的角逐

    VR全景智慧城市:京东推"京东梦"挑战淘宝Buy+ ,VR购物谁主沉浮? VR全景智慧城市是国内首家商业全景平台,结合先进VR虚拟现实技术,以线下实体为依托,将空间还原到线上,用户 ...

  8. 3.Node.js 自定义微信菜单

    文章目录:         1.Node.js 接入微信公众平台开发         2.Node.js access_token的获取.存储及更新         3.Node.js 自定义微信菜单 ...

  9. Java代码编写规范(不是标准规范,自行整理,无须纠结)

    最近回过头来给以前的项目增加功能,发现之前写的注释非常不全,代码也非常的不整洁,有些地方写的''窝七八烂的,看着很不舒服:又恰好经理最近也经常跟我提起代码规范,我们就讨论了一下代码规范的重要性和必要性 ...

  10. BOM(2)

    Window 子对象 (1)Location 对象 Location 对象包含有关当前 URL(统一资源定位符) 的信息.(Uniform Resource Location) Location 对象 ...