protoc-gen-erlang简单调整

前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));
	}
}


实际上改的东西不多,不过总算可以用了 哈哈。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值