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 = 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在檢索到'{'之后開始對module定義的分析,至'}'結束這個module的定義。
因為dsl語言本身的特性,module中只有函數定義,struct中變量定義。所以在module中,只需要分析函數定義。
self.machine = func(),對函數分析器的定義如下:
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因為無需考慮其他的語法要素的區分,函數定義的分析只需要考慮依次提取返回值類型,函數名,(,參數定義,),;函數定義結束。符號表示如下:
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 Falseif ch == ';':self.struct.append(self.argvdef)self.argvdef = []if ch == '}':return Trueself.keyworld += chreturn False對于struct中的變量定義,同樣以'type name;'的方式直接分割。
之后是對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之后分別進入對應分支。
之后是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展開討論。
轉載于:https://www.cnblogs.com/qianqians/p/4255034.html
總結
以上是生活随笔為你收集整理的juggle dsl语法介绍及codegen浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无线路由器说说2.4G和5G Wi-Fi
- 下一篇: dump文件的生成及的分析