Home | History | Annotate | Download | only in compiler
      1 /*
      2  *
      3  * Copyright 2015, Google Inc.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions are
      8  * met:
      9  *
     10  *     * Redistributions of source code must retain the above copyright
     11  * notice, this list of conditions and the following disclaimer.
     12  *     * Redistributions in binary form must reproduce the above
     13  * copyright notice, this list of conditions and the following disclaimer
     14  * in the documentation AN/or other materials provided with the
     15  * distribution.
     16  *     * Neither the name of Google Inc. nor the names of its
     17  * contributors may be used to endorse or promote products derived from
     18  * this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  *
     32  */
     33 
     34 #include <map>
     35 #include <cctype>
     36 #include <sstream>
     37 
     38 #include "src/compiler/go_generator.h"
     39 
     40 template <class T>
     41 grpc::string as_string(T x) {
     42 	std::ostringstream out;
     43 	out << x;
     44 	return out.str();
     45 }
     46 
     47 inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
     48   return method->ClientStreaming() && !method->ServerStreaming();
     49 }
     50 
     51 inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
     52   return !method->ClientStreaming() && method->ServerStreaming();
     53 }
     54 
     55 namespace grpc_go_generator {
     56 
     57 // Returns string with first letter to lowerCase
     58 grpc::string unexportName(grpc::string s) {
     59 	if (s.empty())
     60 		return s;
     61 	s[0] = static_cast<char>(std::tolower(s[0]));
     62 	return s;
     63 }
     64 
     65 // Returns string with first letter to uppercase
     66 grpc::string exportName(grpc::string s) {
     67 	if (s.empty())
     68 		return s;
     69 	s[0] = static_cast<char>(std::toupper(s[0]));
     70 	return s;
     71 }
     72 
     73 // Generates imports for the service
     74 void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer,
     75                      std::map<grpc::string, grpc::string> vars) {
     76 	vars["filename"] = file->filename();
     77 	printer->Print("//Generated by gRPC Go plugin\n");
     78 	printer->Print("//If you make any local changes, they will be lost\n");
     79 	printer->Print(vars, "//source: $filename$\n\n");
     80 	printer->Print(vars, "package $Package$\n\n");
     81 	if (file->additional_headers() != "") {
     82 		printer->Print(file->additional_headers().c_str());
     83 		printer->Print("\n\n");
     84 	}
     85 	printer->Print("import (\n");
     86 	printer->Indent();
     87 	printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n");
     88 	printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n");
     89 	printer->Outdent();
     90 	printer->Print(")\n\n");
     91 }
     92 
     93 // Generates Server method signature source
     94 void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
     95                                    std::map<grpc::string, grpc::string> vars) {
     96 	vars["Method"] = exportName(method->name());
     97 	vars["Request"] = method->get_input_type_name();
     98 	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
     99 	if (method->NoStreaming()) {
    100 		printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
    101 	} else if (ServerOnlyStreaming(method)) {
    102 		printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
    103 	} else {
    104 		printer->Print(vars, "$Method$($Service$_$Method$Server) error");
    105 	}
    106 }
    107 
    108 void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
    109                           std::map<grpc::string, grpc::string> vars) {
    110 	vars["Method"] = exportName(method->name());
    111 	vars["Request"] = method->get_input_type_name();
    112 	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
    113 	vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
    114 	vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
    115 	if (method->NoStreaming()) {
    116 		printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
    117 		printer->Indent();
    118 		printer->Print(vars, "in := new($Request$)\n");
    119 		printer->Print("if err := dec(in); err != nil { return nil, err }\n");
    120 		printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n");
    121 		printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n");
    122 		printer->Indent();
    123 		printer->Print("Server: srv,\n");
    124 		printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n");
    125 		printer->Outdent();
    126 		printer->Print("}\n\n");
    127 		printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n");
    128 		printer->Indent();
    129 		printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n");
    130 		printer->Outdent();
    131 		printer->Print("}\n");
    132 		printer->Print("return interceptor(ctx, in, info, handler)\n");
    133 		printer->Outdent();
    134 		printer->Print("}\n\n");
    135 		return;
    136 	}
    137 	vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
    138 	printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
    139 	printer->Indent();
    140 	if (ServerOnlyStreaming(method)) {
    141 		printer->Print(vars, "m := new($Request$)\n");
    142 		printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n");
    143 		printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n");
    144 	} else {
    145 		printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n");
    146 	}
    147 	printer->Outdent();
    148 	printer->Print("}\n\n");
    149 
    150 	bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method);
    151 	bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method);
    152 	bool genSendAndClose = ClientOnlyStreaming(method);
    153 
    154 	printer->Print(vars, "type $Service$_$Method$Server interface { \n");
    155 	printer->Indent();
    156 	if (genSend) {
    157 		printer->Print(vars, "Send(* $Response$) error\n");
    158 	}
    159 	if (genRecv) {
    160 		printer->Print(vars, "Recv() (* $Request$, error)\n");
    161 	}
    162 	if (genSendAndClose) {
    163 		printer->Print(vars, "SendAndClose(* $Response$) error\n");
    164 	}
    165 	printer->Print(vars, "$grpc$.ServerStream\n");
    166 	printer->Outdent();
    167 	printer->Print("}\n\n");
    168 
    169 	printer->Print(vars, "type $StreamType$ struct {\n");
    170 	printer->Indent();
    171 	printer->Print(vars, "$grpc$.ServerStream\n");
    172 	printer->Outdent();
    173 	printer->Print("}\n\n");
    174 
    175 	if (genSend) {
    176 		printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n");
    177 		printer->Indent();
    178 		printer->Print("return x.ServerStream.SendMsg(m)\n");
    179 		printer->Outdent();
    180 		printer->Print("}\n\n");
    181 	}
    182 	if (genRecv) {
    183 		printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n");
    184 		printer->Indent();
    185 		printer->Print(vars, "m := new($Request$)\n");
    186 		printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n");
    187 		printer->Print("return m, nil\n");
    188 		printer->Outdent();
    189 		printer->Print("}\n\n");
    190 	}
    191 	if (genSendAndClose) {
    192 		printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n");
    193 		printer->Indent();
    194 		printer->Print("return x.ServerStream.SendMsg(m)\n");
    195 		printer->Outdent();
    196 		printer->Print("}\n\n");
    197 	}
    198 
    199 }
    200 
    201 // Generates Client method signature source
    202 void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
    203                                    std::map<grpc::string, grpc::string> vars) {
    204 	vars["Method"] = exportName(method->name());
    205 	vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
    206 	if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
    207 		vars["Request"] = "";
    208 	}
    209 	vars["Response"] = "* " + method->get_output_type_name();
    210 	if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) {
    211 		vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
    212 	}
    213 	printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
    214 }
    215 
    216 // Generates Client method source
    217 void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
    218                           std::map<grpc::string, grpc::string> vars) {
    219 	printer->Print(vars, "func (c *$ServiceUnexported$Client) ");
    220 	GenerateClientMethodSignature(method, printer, vars);
    221 	printer->Print(" {\n");
    222 	printer->Indent();
    223 	vars["Method"] = exportName(method->name());
    224 	vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
    225 	vars["Response"] = method->get_output_type_name();
    226 	vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
    227 	if (method->NoStreaming()) {
    228 		printer->Print(vars, "out := new($Response$)\n");
    229 		printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
    230 		printer->Print("if err != nil { return nil, err }\n");
    231 		printer->Print("return out, nil\n");
    232 		printer->Outdent();
    233 		printer->Print("}\n\n");
    234 		return;
    235 	}
    236 	vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client";
    237 	printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n");
    238 	printer->Print("if err != nil { return nil, err }\n");
    239 
    240 	printer->Print(vars, "x := &$StreamType${stream}\n");
    241 	if (ServerOnlyStreaming(method)) {
    242 		printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
    243 		printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
    244 	}
    245 	printer->Print("return x,nil\n");
    246 	printer->Outdent();
    247 	printer->Print("}\n\n");
    248 
    249 	bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method);
    250 	bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method);
    251 	bool genCloseAndRecv = ClientOnlyStreaming(method);
    252 
    253 	//Stream interface
    254 	printer->Print(vars, "type $Service$_$Method$Client interface {\n");
    255 	printer->Indent();
    256 	if (genSend) {
    257 		printer->Print(vars, "Send(*$Request$) error\n");
    258 	}
    259 	if (genRecv) {
    260 		printer->Print(vars, "Recv() (*$Response$, error)\n");
    261 	}
    262 	if (genCloseAndRecv) {
    263 		printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n");
    264 	}
    265 	printer->Print(vars, "$grpc$.ClientStream\n");
    266 	printer->Outdent();
    267 	printer->Print("}\n\n");
    268 
    269 	//Stream Client
    270 	printer->Print(vars, "type $StreamType$ struct{\n");
    271 	printer->Indent();
    272 	printer->Print(vars, "$grpc$.ClientStream\n");
    273 	printer->Outdent();
    274 	printer->Print("}\n\n");
    275 
    276 	if (genSend) {
    277 		printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n");
    278 		printer->Indent();
    279 		printer->Print("return x.ClientStream.SendMsg(m)\n");
    280 		printer->Outdent();
    281 		printer->Print("}\n\n");
    282 	}
    283 
    284 	if (genRecv) {
    285 		printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n");
    286 		printer->Indent();
    287 		printer->Print(vars, "m := new($Response$)\n");
    288 		printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
    289 		printer->Print("return m, nil\n");
    290 		printer->Outdent();
    291 		printer->Print("}\n\n");
    292 	}
    293 
    294 	if (genCloseAndRecv) {
    295 		printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n");
    296 		printer->Indent();
    297 		printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
    298 		printer->Print(vars, "m := new ($Response$)\n");
    299 		printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
    300 		printer->Print("return m, nil\n");
    301 		printer->Outdent();
    302 		printer->Print("}\n\n");
    303 	}
    304 }
    305 
    306 // Generates client API for the service
    307 void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer,
    308                      std::map<grpc::string, grpc::string> vars) {
    309 	vars["Service"] = exportName(service->name());
    310 	// Client Interface
    311 	printer->Print(vars, "// Client API for $Service$ service\n");
    312 	printer->Print(vars, "type $Service$Client interface{\n");
    313 	printer->Indent();
    314 	for (int i = 0; i < service->method_count(); i++) {
    315 		GenerateClientMethodSignature(service->method(i).get(), printer, vars);
    316 		printer->Print("\n");
    317 	}
    318 	printer->Outdent();
    319 	printer->Print("}\n\n");
    320 
    321 	// Client structure
    322 	vars["ServiceUnexported"] = unexportName(vars["Service"]);
    323 	printer->Print(vars, "type $ServiceUnexported$Client struct {\n");
    324 	printer->Indent();
    325 	printer->Print(vars, "cc *$grpc$.ClientConn\n");
    326 	printer->Outdent();
    327 	printer->Print("}\n\n");
    328 
    329 	// NewClient
    330 	printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n");
    331 	printer->Indent();
    332 	printer->Print(vars, "return &$ServiceUnexported$Client{cc}");
    333 	printer->Outdent();
    334 	printer->Print("\n}\n\n");
    335 
    336 	int unary_methods = 0, streaming_methods = 0;
    337 	vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc";
    338 	for (int i = 0; i < service->method_count(); i++) {
    339 		auto method = service->method(i);
    340 		if (method->NoStreaming()) {
    341 			vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]";
    342 			unary_methods++;
    343 		} else {
    344 			vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]";
    345 			streaming_methods++;
    346 		}
    347 		GenerateClientMethod(method.get(), printer, vars);
    348 	}
    349 
    350 	//Server Interface
    351 	printer->Print(vars, "// Server API for $Service$ service\n");
    352 	printer->Print(vars, "type $Service$Server interface {\n");
    353 	printer->Indent();
    354 	for (int i = 0; i < service->method_count(); i++) {
    355 		GenerateServerMethodSignature(service->method(i).get(), printer, vars);
    356 		printer->Print("\n");
    357 	}
    358 	printer->Outdent();
    359 	printer->Print("}\n\n");
    360 
    361 	// Server registration.
    362 	printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n");
    363 	printer->Indent();
    364 	printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n");
    365 	printer->Outdent();
    366 	printer->Print("}\n\n");
    367 
    368 	for (int i = 0; i < service->method_count(); i++) {
    369 		GenerateServerMethod(service->method(i).get(), printer, vars);
    370 		printer->Print("\n");
    371 	}
    372 
    373 
    374 	//Service Descriptor
    375 	printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
    376 	printer->Indent();
    377 	printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n");
    378 	printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
    379 	printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
    380 	printer->Indent();
    381 	for (int i = 0; i < service->method_count(); i++) {
    382 		auto method = service->method(i);
    383 		vars["Method"] = method->name();
    384 		vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
    385 		if (method->NoStreaming()) {
    386 			printer->Print("{\n");
    387 			printer->Indent();
    388 			printer->Print(vars, "MethodName: \"$Method$\",\n");
    389 			printer->Print(vars, "Handler: $Handler$, \n");
    390 			printer->Outdent();
    391 			printer->Print("},\n");
    392 		}
    393 	}
    394 	printer->Outdent();
    395 	printer->Print("},\n");
    396 	printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n");
    397 	printer->Indent();
    398 	for (int i = 0; i < service->method_count(); i++) {
    399 		auto method = service->method(i);
    400 		vars["Method"] = method->name();
    401 		vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
    402 		if (!method->NoStreaming()) {
    403 			printer->Print("{\n");
    404 			printer->Indent();
    405 			printer->Print(vars, "StreamName: \"$Method$\",\n");
    406 			printer->Print(vars, "Handler: $Handler$, \n");
    407 			if (ClientOnlyStreaming(method.get())) {
    408 				printer->Print("ClientStreams: true,\n");
    409 			} else if (ServerOnlyStreaming(method.get())) {
    410 				printer->Print("ServerStreams: true,\n");
    411 			} else {
    412 				printer->Print("ServerStreams: true,\n");
    413 				printer->Print("ClientStreams: true,\n");
    414 			}
    415 			printer->Outdent();
    416 			printer->Print("},\n");
    417 		}
    418 	}
    419 	printer->Outdent();
    420 	printer->Print("},\n");
    421 	printer->Outdent();
    422 	printer->Print("}\n\n");
    423 
    424 }
    425 
    426 
    427 // Returns source for the service
    428 grpc::string GenerateServiceSource(grpc_generator::File *file,
    429                                    const grpc_generator::Service *service,
    430                                    grpc_go_generator::Parameters *parameters) {
    431 	grpc::string out;
    432 	auto p = file->CreatePrinter(&out);
    433 	auto printer = p.get();
    434 	std::map<grpc::string, grpc::string> vars;
    435 	vars["Package"] = parameters->package_name;
    436 	vars["grpc"] = "grpc";
    437 	vars["context"] = "context";
    438 	GenerateImports(file, printer, vars);
    439 	if (parameters->custom_method_io_type != "") {
    440 		vars["CustomMethodIO"] = parameters->custom_method_io_type;
    441 	}
    442 	GenerateService(service, printer, vars);
    443 	return out;
    444 }
    445 }// Namespace grpc_go_generator
    446