前2天改动了哈,结果今天试了哈还是有问题,加上之前的一共如下:
1、自定义消息里面如果包含了其他自定义数据结构,就需要把依赖的消息定义放在前面。
2、hrl重复包含的问题,要用宏定义解决。
3、消息decode的时候用到其他消息的时候,用的impl要改成导出的函数。
4、空消息的编码有点问题,回调函数没法生成,它是根据消息内字段来生成的。
5、加上昨天的支持proto的import。
6、消息间相互包含后的调用,在erl里面import其他消息模块(其实import不是很好,如果其他模块有同一个函数可能有问题,最好是在函数调用时候用module:fun不过这个好像很麻烦)。
7、export的时候有个bug,枚举和消息间前缺逗号。
今天又调整了哈,没问题了哈哈,记录下。
其实想传到github的不过搞不囊个来,先放这点吧。
ErlangRecordGenerator.cpp
//宏定义解决hrl重复包含
void ErlangGenerator::define_macro(Printer& out,const FileDescriptor* file) const
{
out.Print("-ifndef($name$_proto).\n"
"-define($name$_proto,$file$_proto).\n\n",
"name",to_atom(module_name(file)),
"file", to_atom(file_basename(file->name())));
}
//宏定义结束
void ErlangGenerator::end_macro(Printer& out,const FileDescriptor* file) const
{
out.Print("-endif.\n");
}
//支持proto的import
void ErlangGenerator::dependency_to_include(Printer& out,const FileDescriptor* import) const
{
out.Print("-include(\"$name$.hrl\").\n\n","name", to_atom(module_name(import)));
}
void ErlangGenerator::generate_header(Printer& out, const FileDescriptor* file) const
{
define_macro(out,file);
for (int i = 0; i < file->dependency_count(); i++) {
dependency_to_include(out,file->dependency(i));
}
for (int i = 0; i < file->enum_type_count(); i++) {
enum_to_typespec(out,file->enum_type(i));
}
std::list<int> msgList;
//按照包含字段的依赖关系调整顺序
for(int i=0; i < file->message_type_count();++i)
{
const Descriptor* msg=file->message_type(i);
bool nested=false;
int count = msg->field_count();
for (int i = 0; i < count; i++)
{
const FieldDescriptor* field = msg->field(i);
if (file->FindMessageTypeByName(field->name())!=NULL)
{
nested=true;
break;
}
}
if (nested)
msgList.push_back(i);
else
msgList.push_front(i);
}
while (!msgList.empty())
{
int index=msgList.front();
msgList.pop_front();
message_to_record(out,file->message_type(index));
}
end_macro(out,file);
}
ErlangSourceGenerator.cpp
void ErlangGenerator::field_to_decode_function(Printer &out, const FieldDescriptor* field) const
{
std::map<string,string> vars;
vars["id"]=int_to_string(field->number());
vars["rec"]=to_atom(normalized_scope(field->containing_type()));
vars["field"] = to_atom(field->name());
vars["type"]=string(kTypeToName[field->type()]);
switch (field->type()) {
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
// No such thing as a packed string/bytes, so we just append/replace multiple instances.
if(field->is_repeated())
out.Print(vars,"($id$,Val,#$rec${$field$=F}=Rec) when is_list(F) -> Rec#$rec${$field$ = Rec#$rec$.$field$ ++ [protocol_buffers:cast($type$,Val)]}\n");
else
out.Print(vars,"($id$,Val,Rec) -> Rec#$rec${$field$ = protocol_buffers:cast($type$,Val)}");
break;
case FieldDescriptor::TYPE_MESSAGE:
// No such thing as a packed series of messages, so just append/replace multiple encounters.
//修正使用其他模块的decode的impl函数
vars["decode"]=decode_name(field->message_type());
if(field->is_repeated())
out.Print(vars,"($id$,{length_encoded,Bin},#$rec${$field$=F}=Rec) when is_list(F) -> Rec#$rec${$field$ = Rec#$rec$.$field$ ++ [$decode$(Bin)]}\n");
else
out.Print(vars,"($id$,{length_encoded,Bin},Rec) -> Rec#$rec${$field$ = $decode$(Bin)}");
break;
case FieldDescriptor::TYPE_ENUM:
// As with integer types, but the additional step of to_enum()
vars["to_enum"]=to_enum_name(field->enum_type());
if(field->is_repeated())
out.Print(vars,"($id$,{varint,Enum},#$rec${$field$=F}=Rec) when is_list(F) -> Rec#$rec${$field$=Rec#$rec$.$field$ ++ [$to_enum$(Enum)]}\n");
else
out.Print(vars,"($id$,{varint,Enum},Rec) -> Rec#$rec${$field$=$to_enum$(Enum)}");
break;
case FieldDescriptor::TYPE_GROUP:
// not supported
break;
default:
if(field->is_repeated())
{
// packed repeated returns array
out.Print(vars," ($id$,{length_encoded,_}=Val,#$rec${$field$=F}=Rec) when is_list(F) -> Rec#$rec${$field$ = Rec#$rec$.$field$ ++ protocol_buffers:cast($type$,Val)};\n");
// repeated that's not packed does not return an array
out.Print(vars," ($id$,Val,#$rec${$field$=F}=Rec) when is_list(F) -> Rec#$rec${$field$ = Rec#$rec$.$field$ ++ [protocol_buffers:cast($type$,Val)]}\n");
} else {
out.Print(vars,"($id$,Val,Rec) -> Rec#$rec${$field$ = protocol_buffers:cast($type$,Val)}");
}
}
}
void ErlangGenerator::encode_decode_for_message(Printer& out, const Descriptor* d) const
{
for(int i=0; i < d->enum_type_count();++i)
encode_decode_for_enum(out,d->enum_type(i));
for(int i=0; i< d->nested_type_count();++i)
encode_decode_for_message(out,d->nested_type(i));
// decode functions
out.Print("$function$(B) ->\n"
" case $function_impl$(B) of\n"
" undefined -> #$msg${};\n"
" Any -> Any\n"
" end.\n\n"
"$function_impl$(<<>>) -> undefined;\n"
"$function_impl$(Binary) ->\n"
" protocol_buffers:decode(Binary,#$msg${},\n"
" fun",
"function",decode_name(d),
"function_impl",decode_impl_name(d),
"msg",to_atom(normalized_scope(d)));
for(int i=0; i< d->field_count();++i)
{
field_to_decode_function(out,d->field(i));
if(i < d->field_count()-1)
{
out.PrintRaw(";\n ");
}
}
//生成不包含任何字段的消息decode回调函数
if (d->field_count()==0)
{
out.Print("(_,_,Rec) -> Rec#$rec${}","rec",to_atom(normalized_scope(d)));
}
out.PrintRaw("\n end).\n\n");
// encode functions
out.Print("$function$(undefined) -> undefined;\n"
"$function$(R) when is_record(R,$rec$) ->\n"
" [\n",
"function",encode_name(d),
"rec",to_atom(normalized_scope(d)));
for(int i=0; i< d->field_count();++i)
{
const FieldDescriptor* field=d->field(i);
std::map<string,string> vars;
vars["id"]=int_to_string(field->number());
vars["rec"]=to_atom(normalized_scope(field->containing_type()));
vars["field"] = to_atom(field->name());
vars["type"]=string(kTypeToName[field->type()]);
switch(field->type()) {
case FieldDescriptor::TYPE_ENUM:
vars["from_enum"]=from_enum_name(field->enum_type());
if(field->is_repeated())
{
out.Print(vars," [protocol_buffers:encode($id$,int32,$from_enum$(X)) || X <- R#$rec$.$field$]");
} else {
out.Print(vars," protocol_buffers:encode($id$,int32,$from_enum$(R#$rec$.$field$))");
}
break;
case FieldDescriptor::TYPE_MESSAGE:
vars["encode"]=encode_name(field->message_type());
if(field->is_repeated())
out.Print(vars," [ protocol_buffers:encode($id$,length_encoded,$encode$(X)) || X <- R#$rec$.$field$]");
else
out.Print(vars," protocol_buffers:encode($id$,length_encoded,$encode$(R#$rec$.$field$))");
break;
case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_STRING:
if(field->is_repeated())
out.Print(vars," [ protocol_buffers:encode($id$,length_encoded,X) || X <- R#$rec$.$field$]");
else
out.Print(vars," protocol_buffers:encode($id$,length_encoded,R#$rec$.$field$)");
break;
default:
out.Print(vars," protocol_buffers:encode($id$,$type$,R#$rec$.$field$)");
}
if(i<d->field_count()-1)
out.PrintRaw(",\n");
}
out.PrintRaw("\n ].\n\n");
}
void ErlangGenerator::generate_source(Printer& out, const FileDescriptor* file) const
{
out.Print("-module($module$).\n"
"-include(\"$module$.hrl\").\n\n"
"-export([\n"
,"module",module_name(file));
for(int i=0; i < file->enum_type_count();++i)
{
if(i >0)
out.PrintRaw(",\n");
export_for_enum(out,file->enum_type(i));
}
for(int i=0; i < file->message_type_count();++i)
{
if(file->enum_type_count()>0||i >0)
out.PrintRaw(",\n");
export_for_message(out,file->message_type(i));
}
out.PrintRaw("]).\n\n");
//导入其他依赖模块的所有函数
for (int i=0; i<file->dependency_count();++i)
{
const FileDescriptor* importFile=file->dependency(i);
out.Print("-import($import$,[\n","import",module_name(importFile));
for(int i=0; i < importFile->enum_type_count();++i)
{
if(i >0)
out.PrintRaw(",\n");
export_for_enum(out,importFile->enum_type(i));
}
for(int i=0; i < importFile->message_type_count();++i)
{
if(i >0)
out.PrintRaw(",\n");
export_for_message(out,importFile->message_type(i));
}
out.PrintRaw("]).\n\n");
}
for(int i=0; i < file->enum_type_count();++i)
{
encode_decode_for_enum(out,file->enum_type(i));
}
for(int i=0; i < file->message_type_count();++i) {
encode_decode_for_message(out,file->message_type(i));
}
}
实际上改的东西不多,不过总算可以用了 哈哈。