juggle dsl语法介绍及codegen浅析
juggle语法规范如下:
类型:
bool -> in cpp bool
int -> in cpp int64
float -> in cpp double
string -> in cpp std::string
array -> in cpp std::vector
struct -> in cpp object
函数的定义则同c语言:void rpctest1(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);
整体的juggle语法如下:
module juggle{
void rpctest1(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);
void rpctest2(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);
}
其中module对应c++中的class,并且在服务器端会被codegen实现为一个单件,无需用户定义句柄有codegen生成对应的create代码。
codegen会依据module中函数定义,生成如下代码:
#include <juggle.h>
class juggle: public module{
public:
juggle() : module(ch, juggleuuid::UUID()){
_service_handle->register_module_method(juggle_rpctest1,boost::bind(&juggle::call_rpctest1, this, _1));
_service_handle->register_module_method(juggle_rpctest2,boost::bind(&juggle::call_rpctest2, this, _1));
}
~juggle(){
}
virtual void rpctest1(int64_t argv1,bool argv2,std::string argv3,double argv4,std::vector<int64_t> argv5) = 0;
void call_rpctest1(boost::shared_ptr<channel> ch, boost::shared_ptr<object> v){
auto argv1 = (*v)["argv1"].asint();
auto argv2 = (*v)["argv2"].asbool();
auto argv3 = (*v)["argv3"].asstring();
auto argv4 = (*v)["argv4"].asfloat();
std::vector<int64_t> argv5;
for(int i = 0; i < (*v)["argv5"].size(); i++){
v.push_back((*v)["argv5"][i].asint());
}
auto ret = rpctest1(argv1, argv2, argv3, argv4, argv5);
boost::shared_ptr<object> r = boost::make_shared<object>();
(*r)["suuid"] = (*v)["suuid"];
(*r)["method"] = (*value)["method"];
(*r)["ret"] = ret;
ch->push(r);
}
virtual void rpctest2(int64_t argv1,bool argv2,std::string argv3,double argv4,std::vector<int64_t> argv5) = 0;
void call_rpctest2(boost::shared_ptr<channel> ch, boost::shared_ptr<object> v){
auto argv1 = (*v)["argv1"].asint();
auto argv2 = (*v)["argv2"].asbool();
auto argv3 = (*v)["argv3"].asstring();
auto argv4 = (*v)["argv4"].asfloat();
std::vector<int64_t> argv5;
for(int i = 0; i < (*v)["argv5"].size(); i++){
v.push_back((*v)["argv5"][i].asint());
}
auto ret = rpctest2(argv1, argv2, argv3, argv4, argv5);
boost::shared_ptr<object> r = boost::make_shared<object>();
(*r)["suuid"] = (*v)["suuid"];
(*r)["method"] = (*value)["method"];
(*r)["ret"] = ret;
ch->push(r);
}
};
可以看到,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的分析代码如下:
class module(object):
def __init__(self):
self.keyworld = ''
self.name = ''
self.module = []
self.machine = None def push(self, ch):
if ch == '}':
self.machine = None
return True if self.machine is not None:
if self.machine.push(ch):
self.module.append(self.machine.func)
self.machine.clear()
else:
if ch == '{':
self.name = deleteNoneSpacelstrip(self.keyworld)
self.keyworld = ''
self.machine = func()
return False self.keyworld += ch return False
在检索到'{'之后开始对module定义的分析,至'}'结束这个module的定义。
因为dsl语言本身的特性,module中只有函数定义,struct中变量定义。所以在module中,只需要分析函数定义。
self.machine = func(),对函数分析器的定义如下:
class func(object):
def __init__(self):
self.keyworld = ''
self.func = []
self.argvtuple = None def clear(self):
self.keyworld = ''
self.func = []
self.argvtuple = None def push(self, ch):
if ch == ' ' or ch == '\0':
self.keyworld = deleteNoneSpacelstrip(self.keyworld)
if self.keyworld != '':
if self.argvtuple is None:
self.func.append(self.keyworld)
else:
self.argvtuple.append(self.keyworld)
self.keyworld = ''
return False if ch == ',':
if self.keyworld != '':
self.argvtuple.append(deleteNoneSpacelstrip(self.keyworld))
self.func.append(self.argvtuple)
self.keyworld = ''
self.argvtuple = []
return False if ch == '(':
self.func.append(deleteNoneSpacelstrip(self.keyworld))
self.argvtuple = []
self.keyworld = ''
return False if ch == ')':
if self.keyworld != '':
self.argvtuple.append(deleteNoneSpacelstrip(self.keyworld))
self.func.append(self.argvtuple)
self.keyworld = ''
return False if ch == ';':
return True self.keyworld += ch return False
因为无需考虑其他的语法要素的区分,函数定义的分析只需要考虑依次提取返回值类型,函数名,(,参数定义,),;函数定义结束。符号表示如下:
rettype funcname(argvlist...);
之后是对struct的分析,与module类似,在struct之后的既是struct name的定义,之后是'{'开始struct的定义,之'}'结束此struct的定义,代码如下:
class struct(object):
def __init__(self):
self.keyworld = ''
self.name = ''
self.struct = []
self.argvdef = [] def push(self, ch):
if ch == ' ' or ch == '\0':
if self.keyworld != '':
self.argvdef.append(self.keyworld) if ch == '{':
self.name = deleteNoneSpacelstrip(self.keyworld)
self.keyworld = ''
return False if ch == ';':
self.struct.append(self.argvdef)
self.argvdef = [] if ch == '}':
return True self.keyworld += ch return False
对于struct中的变量定义,同样以'type name;'的方式直接分割。
之后是对jeggle文件的整体分析:
class statemachine(object):
Moduledefine = 0
Funcdefine = 1 def __init__(self):
self.keyworld = ''
self.module = {}
self.struct = {}
self.machine = None def push(self, ch):
if self.machine is not None:
if self.machine.push(ch):
if isinstance(self.machine, module):
self.module[self.machine.name] = self.machine.module
self.machine = None
if isinstance(self.machine, struct):
self.struct[self.machine.name] = self.machine.struct
self.machine = None
else:
self.keyworld += ch if self.keyworld == 'module':
self.machine = module()
self.keyworld = '' if self.keyworld == 'struct':
self.machine = struct()
self.keyworld = '' def getmodule(self):
return self.module def getstruct(self):
return self.struct def syntaxanalysis(self, genfilestr):
for str in genfilestr:
for ch in str:
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浅析的更多相关文章
- Swift翻译之-Swift语法入门 Swift语法介绍
目录[-] Hello world - Swift 简单赋值 控制流 函数与闭包 对象和类 枚举与结构 协议和扩展 泛型 2014.6.3日,苹果公布最新编程语言Swift,Swift是一种新的编程语 ...
- flex弹性布局语法介绍及使用
一.语法介绍 Flex布局(弹性布局) ,一种新的布局解决方案 可简单.快速的实现网页布局 目前市面浏览器已全部支持1.指定容器为flex布局 display: flex; Webkit内核的浏览器, ...
- freemarker语法介绍及其入门教程实例
# freemarker语法介绍及其入门教程实例 # ## FreeMarker标签使用 #####一.FreeMarker模板文件主要有4个部分组成</br>#### 1.文本,直接输 ...
- QSS类的用法及基本语法介绍
QSS类的用法及基本语法介绍 目录 1. 何为Qt样式表2. 样式表语法基础3. 方箱模型4. 前景与背景5. 创建可缩放样式6. 控制大小7. 处理伪状态8. 使用子部件定义微观样式8.1. 相对定 ...
- MD基本语法介绍
Markdown基本语法介绍 前言 文本编辑器一般用的有富文本编辑器(也就是Word)和md了,但是wold太过于花里胡哨很多功能都用不上,所以就选择md了,简单实用,一对于我来说一般就用标题和列表就 ...
- react的优点:兼容了dsl语法与UI的组件化管理
react的优点:兼容了dsl语法与UI的组件化管理. 组件化管理的dsl描述 UI: 虚拟dom:
- Markdown 语法介绍
Markdown 语法介绍 from:https://coding.net/help/doc/project/markdown.html 文章内容 1 Markdown 语法介绍 1.1 标题 1.2 ...
- css基本概念与css核心语法介绍
css基本概念 css是什么?不需要了解太多文字类介绍,记住css是层叠样式表,HTML是页面结构,css负责页面样式,javascrt负责静态页面的交互.CSS 能够对网页中元素位置的排版进行像素级 ...
- c基本语法介绍
c语言基本语法介绍 1.把常量定义为大写字母形式,是一个很好的编程实践.
随机推荐
- Linux下的Jenkins+Tomcat+Maven+Gitlab+Shell环境的搭建使用(jenkins自动化部署)
jenkins自动化部署 目标:jenkins上点构建(也可以自动检查代码变化自动构建)>>>项目部署完成. 一.安装jenkins 1.下载jenkins 这里我选择的是war包安 ...
- 转:Centos6.5_x86安装Redis。
Redis是一个高性能的,开源key-value型数据库.是构建高性能,可扩展的Web应用的完美解决方案,可以内存存储亦可持久化存储.因为要使用跨进程,跨服务级别的数据缓存,在对比多个方案后,决定使用 ...
- RabbitMQ集群和失败处理
RabbitMQ内建集群的设计用于完成两个目标:允许消费者和生产者在RabbitMQ节点在奔溃的情况下继续运行,以及通过添加更多的节点来线性扩展消息通信的吞吐量.当失去一个RabbitMQ节点时客户端 ...
- 从编译器角度理解C++中的引用和指针
欲分析指针和引用,则要分析变量名和地址之间的关系(不管你理解还是不理解,无论你是从老师那里听到的,还是网上看到的,应该都知道两句话:1. 指针就是地址,2.引用就是给变量起个别名) 所以我们就要来分析 ...
- Eclipse Java 关联源码
今天打代码的时候打算看看Java的源码是怎么实现的 没想到还没关联源码 遇到上面的情况只需要关联下源码就可以对着方法按F3查看JAVA的开源代码. 解决上面如下: 找到jdk的安装目录 找到src.z ...
- DDD理论学习系列(3)-- 限界上下文
1. 引言 限界上下文可以拆分为两个词,限界和上下文. 限界:是指一个界限,具体的某一个范围. 上下文:个人理解就是语境. 比如我们常说的段子: "我想静静." 这个句子一般是想表 ...
- Log4net日志记录、详细配置(自己使用)
[来自百度百科的一句介绍]log4net库是Apache log4j框架在Microsoft .NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控制台.文件.数据库等)的工具. 1.首先添 ...
- TCP协议随笔
传输控制协议TCP是面向连接.保证高可靠性(数据无丢失.数据无失序.数据无错误.数据无重复到达)传输层协议.TCP/IP结构对应OSITCP/IP ...
- 025 hibernate悲观锁、乐观锁
Hibernate谈到悲观锁.乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差 并发性:当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了.称为并发性不好 数据库隔离级 ...
- how to install Web logic Server (WLS)
a) Download artificts from: http://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-main ...