juggle dsl语法介绍及codegen浅析
juggle語(yǔ)法規(guī)范如下:
類(lèi)型:
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函數(shù)的定義則同c語(yǔ)言:void rpctest1(int argv1, bool argv2, string argv3, float argv4, array<int> argv5);
整體的juggle語(yǔ)法如下:
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對(duì)應(yīng)c++中的class,并且在服務(wù)器端會(huì)被codegen實(shí)現(xiàn)為一個(gè)單件,無(wú)需用戶(hù)定義句柄有codegen生成對(duì)應(yīng)的create代碼。
codegen會(huì)依據(jù)module中函數(shù)定義,生成如下代碼:
#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實(shí)現(xiàn)了網(wǎng)絡(luò)層面的消息響應(yīng)、協(xié)議pack/unpack以及對(duì)rpc函數(shù)的調(diào)用,返回值封包發(fā)送的代碼。用戶(hù)只需要繼承module并實(shí)現(xiàn)對(duì)應(yīng)的rpc函數(shù)。
其中對(duì)于obejct的定義見(jiàn) https://github.com/NetEase/fossilizid/blob/master/juggle/interface/object.h
我定義了一個(gè)純虛類(lèi),用于規(guī)范一個(gè)通信協(xié)議參數(shù)入棧和訪問(wèn)的接口
然后定義了一個(gè)channel?https://github.com/NetEase/fossilizid/blob/master/juggle/interface/channel.h
用于規(guī)范通信的接口
對(duì)于通信而言,push/pop是非常上層的一個(gè)接口,但是這樣的設(shè)計(jì)目的在于提供一個(gè)寬泛的抽象,這里通信的可以是一個(gè)消息隊(duì)列,一個(gè)基于共享內(nèi)存的本地跨進(jìn)程通信,同樣也可以是socket。
btw:另一個(gè)原因是我自己封裝的網(wǎng)絡(luò)庫(kù)的長(zhǎng)相是這樣的?https://github.com/NetEase/fossilizid/tree/master/remoteq, remotoq提供的通信句柄正是channel,而提供的訪問(wèn)接口則是push/pop。并且通過(guò)模板參數(shù)配置了網(wǎng)絡(luò)協(xié)議的pack/unpack。我這么實(shí)現(xiàn)是為了方便代碼復(fù)用。
然后是對(duì)dsl語(yǔ)言的編譯:
juggle的語(yǔ)法定義的關(guān)鍵字,除了變量類(lèi)型,就只有module和struct。對(duì)于一個(gè)module的定義,在module之后是是這個(gè)module的命名,之后是'{'表示此module定義開(kāi)始,至'}'表示此module定義結(jié)束。module的分析代碼如下:
class module(object):def __init__(self):self.keyworld = ''self.name = ''self.module = []self.machine = Nonedef push(self, ch):if ch == '}':self.machine = Nonereturn Trueif 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 Falseself.keyworld += chreturn False在檢索到'{'之后開(kāi)始對(duì)module定義的分析,至'}'結(jié)束這個(gè)module的定義。
因?yàn)閐sl語(yǔ)言本身的特性,module中只有函數(shù)定義,struct中變量定義。所以在module中,只需要分析函數(shù)定義。
self.machine = func(),對(duì)函數(shù)分析器的定義如下:
class func(object):def __init__(self):self.keyworld = ''self.func = []self.argvtuple = Nonedef clear(self):self.keyworld = ''self.func = []self.argvtuple = Nonedef 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 Falseif ch == ',':if self.keyworld != '':self.argvtuple.append(deleteNoneSpacelstrip(self.keyworld))self.func.append(self.argvtuple)self.keyworld = ''self.argvtuple = []return Falseif ch == '(':self.func.append(deleteNoneSpacelstrip(self.keyworld))self.argvtuple = []self.keyworld = ''return Falseif ch == ')':if self.keyworld != '':self.argvtuple.append(deleteNoneSpacelstrip(self.keyworld))self.func.append(self.argvtuple)self.keyworld = ''return Falseif ch == ';':return Trueself.keyworld += chreturn False因?yàn)闊o(wú)需考慮其他的語(yǔ)法要素的區(qū)分,函數(shù)定義的分析只需要考慮依次提取返回值類(lèi)型,函數(shù)名,(,參數(shù)定義,),;函數(shù)定義結(jié)束。符號(hào)表示如下:
rettype funcname(argvlist...);
之后是對(duì)struct的分析,與module類(lèi)似,在struct之后的既是struct name的定義,之后是'{'開(kāi)始struct的定義,之'}'結(jié)束此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 Falseif ch == ';':self.struct.append(self.argvdef)self.argvdef = []if ch == '}':return Trueself.keyworld += chreturn False對(duì)于struct中的變量定義,同樣以'type name;'的方式直接分割。
之后是對(duì)jeggle文件的整體分析:
class statemachine(object):Moduledefine = 0Funcdefine = 1def __init__(self):self.keyworld = ''self.module = {}self.struct = {}self.machine = Nonedef 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.moduleself.machine = Noneif isinstance(self.machine, struct):self.struct[self.machine.name] = self.machine.structself.machine = Noneelse:self.keyworld += chif self.keyworld == 'module':self.machine = module()self.keyworld = ''if self.keyworld == 'struct':self.machine = struct()self.keyworld = ''def getmodule(self):return self.moduledef getstruct(self):return self.structdef syntaxanalysis(self, genfilestr):for str in genfilestr:for ch in str:self.push(ch)檢索到module和struct之后分別進(jìn)入對(duì)應(yīng)分支。
之后是codegen的代碼見(jiàn):
https://github.com/NetEase/fossilizid/blob/master/juggle/rpcmake/codegen.py
和之前的http://www.cnblogs.com/qianqians/p/4184441.html對(duì)比可以看到精簡(jiǎn)之后的dsl語(yǔ)法要方便分析許多,實(shí)作代碼也要清晰不少。
和之前為c++添加rpccall的計(jì)劃相比,現(xiàn)在的dsl語(yǔ)言便于提供其他語(yǔ)言的擴(kuò)展,同時(shí)編譯器也會(huì)好些很多。
btw:現(xiàn)在的dsl語(yǔ)法非常之強(qiáng)類(lèi)型,尤其是帶模板參數(shù)的array<int>,有用過(guò)protobuf和thrift的同學(xué)應(yīng)該可以對(duì)比去其中的區(qū)別,希望大家能對(duì)如何設(shè)計(jì)一個(gè)好用的dsl展開(kāi)討論。
轉(zhuǎn)載于:https://www.cnblogs.com/qianqians/p/4255034.html
總結(jié)
以上是生活随笔為你收集整理的juggle dsl语法介绍及codegen浅析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 无线路由器说说2.4G和5G Wi-Fi
- 下一篇: dump文件的生成及的分析