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 namespace grpc_go_generator {
     48 
     49 // Returns string with first letter to lowerCase
     50 grpc::string unexportName(grpc::string s) {
     51 	if (s.empty())
     52 		return s;
     53 	s[0] = static_cast<char>(std::tolower(s[0]));
     54 	return s;
     55 }
     56 
     57 // Returns string with first letter to uppercase
     58 grpc::string exportName(grpc::string s) {
     59 	if (s.empty())
     60 		return s;
     61 	s[0] = static_cast<char>(std::toupper(s[0]));
     62 	return s;
     63 }
     64 
     65 // Generates imports for the service
     66 void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer,
     67                      std::map<grpc::string, grpc::string> vars) {
     68 	vars["filename"] = file->filename();
     69 	printer->Print("//Generated by gRPC Go plugin\n");
     70 	printer->Print("//If you make any local changes, they will be lost\n");
     71 	printer->Print(vars, "//source: $filename$\n\n");
     72 	printer->Print(vars, "package $Package$\n\n");
     73 	if (file->additional_imports() != "") {
     74 		printer->Print(file->additional_imports().c_str());
     75 		printer->Print("\n\n");
     76 	}
     77 	printer->Print("import (\n");
     78 	printer->Indent();
     79 	printer->Print(vars, "$context$ \"golang.org/x/net/context\"\n");
     80 	printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n");
     81 	printer->Outdent();
     82 	printer->Print(")\n\n");
     83 }
     84 
     85 // Generates Server method signature source
     86 void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
     87                                    std::map<grpc::string, grpc::string> vars) {
     88 	vars["Method"] = exportName(method->name());
     89 	vars["Request"] = method->input_name();
     90 	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
     91 	if (method->NoStreaming()) {
     92 		printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
     93 	} else if (method->ServerOnlyStreaming()) {
     94 		printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
     95 	} else {
     96 		printer->Print(vars, "$Method$($Service$_$Method$Server) error");
     97 	}
     98 }
     99 
    100 void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
    101                           std::map<grpc::string, grpc::string> vars) {
    102 	vars["Method"] = exportName(method->name());
    103 	vars["Request"] = method->input_name();
    104 	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
    105 	vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
    106 	vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
    107 	if (method->NoStreaming()) {
    108 		printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n");
    109 		printer->Indent();
    110 		printer->Print(vars, "in := new($Request$)\n");
    111 		printer->Print("if err := dec(in); err != nil { return nil, err }\n");
    112 		printer->Print(vars, "if interceptor == nil { return srv.($Service$Server).$Method$(ctx, in) }\n");
    113 		printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n");
    114 		printer->Indent();
    115 		printer->Print("Server: srv,\n");
    116 		printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n");
    117 		printer->Outdent();
    118 		printer->Print("}\n\n");
    119 		printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n");
    120 		printer->Indent();
    121 		printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(* $Request$))\n");
    122 		printer->Outdent();
    123 		printer->Print("}\n");
    124 		printer->Print("return interceptor(ctx, in, info, handler)\n");
    125 		printer->Outdent();
    126 		printer->Print("}\n\n");
    127 		return;
    128 	}
    129 	vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
    130 	printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
    131 	printer->Indent();
    132 	if (method->ServerOnlyStreaming()) {
    133 		printer->Print(vars, "m := new($Request$)\n");
    134 		printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n");
    135 		printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n");
    136 	} else {
    137 		printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n");
    138 	}
    139 	printer->Outdent();
    140 	printer->Print("}\n\n");
    141 
    142 	bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming();
    143 	bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming();
    144 	bool genSendAndClose = method->ClientOnlyStreaming();
    145 
    146 	printer->Print(vars, "type $Service$_$Method$Server interface { \n");
    147 	printer->Indent();
    148 	if (genSend) {
    149 		printer->Print(vars, "Send(* $Response$) error\n");
    150 	}
    151 	if (genRecv) {
    152 		printer->Print(vars, "Recv() (* $Request$, error)\n");
    153 	}
    154 	if (genSendAndClose) {
    155 		printer->Print(vars, "SendAndClose(* $Response$) error\n");
    156 	}
    157 	printer->Print(vars, "$grpc$.ServerStream\n");
    158 	printer->Outdent();
    159 	printer->Print("}\n\n");
    160 
    161 	printer->Print(vars, "type $StreamType$ struct {\n");
    162 	printer->Indent();
    163 	printer->Print(vars, "$grpc$.ServerStream\n");
    164 	printer->Outdent();
    165 	printer->Print("}\n\n");
    166 
    167 	if (genSend) {
    168 		printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n");
    169 		printer->Indent();
    170 		printer->Print("return x.ServerStream.SendMsg(m)\n");
    171 		printer->Outdent();
    172 		printer->Print("}\n\n");
    173 	}
    174 	if (genRecv) {
    175 		printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n");
    176 		printer->Indent();
    177 		printer->Print(vars, "m := new($Request$)\n");
    178 		printer->Print("if err := x.ServerStream.RecvMsg(m); err != nil { return nil, err }\n");
    179 		printer->Print("return m, nil\n");
    180 		printer->Outdent();
    181 		printer->Print("}\n\n");
    182 	}
    183 	if (genSendAndClose) {
    184 		printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n");
    185 		printer->Indent();
    186 		printer->Print("return x.ServerStream.SendMsg(m)\n");
    187 		printer->Outdent();
    188 		printer->Print("}\n\n");
    189 	}
    190 
    191 }
    192 
    193 // Generates Client method signature source
    194 void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
    195                                    std::map<grpc::string, grpc::string> vars) {
    196 	vars["Method"] = exportName(method->name());
    197 	vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]);
    198 	if (method->ClientOnlyStreaming() || method->BidiStreaming()) {
    199 		vars["Request"] = "";
    200 	}
    201 	vars["Response"] = "* " + method->output_name();
    202 	if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) {
    203 		vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
    204 	}
    205 	printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
    206 }
    207 
    208 // Generates Client method source
    209 void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
    210                           std::map<grpc::string, grpc::string> vars) {
    211 	printer->Print(vars, "func (c *$ServiceUnexported$Client) ");
    212 	GenerateClientMethodSignature(method, printer, vars);
    213 	printer->Print(" {\n");
    214 	printer->Indent();
    215 	vars["Method"] = exportName(method->name());
    216 	vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"];
    217 	vars["Response"] = method->output_name();
    218 	vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
    219 	if (method->NoStreaming()) {
    220 		printer->Print(vars, "out := new($Response$)\n");
    221 		printer->Print(vars, "err := $grpc$.Invoke(ctx, \"$FullMethodName$\", in, out, c.cc, opts...)\n");
    222 		printer->Print("if err != nil { return nil, err }\n");
    223 		printer->Print("return out, nil\n");
    224 		printer->Outdent();
    225 		printer->Print("}\n\n");
    226 		return;
    227 	}
    228 	vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client";
    229 	printer->Print(vars, "stream, err := $grpc$.NewClientStream(ctx, &$MethodDesc$, c.cc, \"$FullMethodName$\", opts...)\n");
    230 	printer->Print("if err != nil { return nil, err }\n");
    231 
    232 	printer->Print(vars, "x := &$StreamType${stream}\n");
    233 	if (method->ServerOnlyStreaming()) {
    234 		printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
    235 		printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
    236 	}
    237 	printer->Print("return x,nil\n");
    238 	printer->Outdent();
    239 	printer->Print("}\n\n");
    240 
    241 	bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming();
    242 	bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming();
    243 	bool genCloseAndRecv = method->ClientOnlyStreaming();
    244 
    245 	//Stream interface
    246 	printer->Print(vars, "type $Service$_$Method$Client interface {\n");
    247 	printer->Indent();
    248 	if (genSend) {
    249 		printer->Print(vars, "Send(*$Request$) error\n");
    250 	}
    251 	if (genRecv) {
    252 		printer->Print(vars, "Recv() (*$Response$, error)\n");
    253 	}
    254 	if (genCloseAndRecv) {
    255 		printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n");
    256 	}
    257 	printer->Print(vars, "$grpc$.ClientStream\n");
    258 	printer->Outdent();
    259 	printer->Print("}\n\n");
    260 
    261 	//Stream Client
    262 	printer->Print(vars, "type $StreamType$ struct{\n");
    263 	printer->Indent();
    264 	printer->Print(vars, "$grpc$.ClientStream\n");
    265 	printer->Outdent();
    266 	printer->Print("}\n\n");
    267 
    268 	if (genSend) {
    269 		printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n");
    270 		printer->Indent();
    271 		printer->Print("return x.ClientStream.SendMsg(m)\n");
    272 		printer->Outdent();
    273 		printer->Print("}\n\n");
    274 	}
    275 
    276 	if (genRecv) {
    277 		printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n");
    278 		printer->Indent();
    279 		printer->Print(vars, "m := new($Response$)\n");
    280 		printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
    281 		printer->Print("return m, nil\n");
    282 		printer->Outdent();
    283 		printer->Print("}\n\n");
    284 	}
    285 
    286 	if (genCloseAndRecv) {
    287 		printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n");
    288 		printer->Indent();
    289 		printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
    290 		printer->Print(vars, "m := new ($Response$)\n");
    291 		printer->Print("if err := x.ClientStream.RecvMsg(m); err != nil { return nil, err }\n");
    292 		printer->Print("return m, nil\n");
    293 		printer->Outdent();
    294 		printer->Print("}\n\n");
    295 	}
    296 }
    297 
    298 // Generates client API for the service
    299 void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer,
    300                      std::map<grpc::string, grpc::string> vars) {
    301 	vars["Service"] = exportName(service->name());
    302 	// Client Interface
    303 	printer->Print(vars, "// Client API for $Service$ service\n");
    304 	printer->Print(vars, "type $Service$Client interface{\n");
    305 	printer->Indent();
    306 	for (int i = 0; i < service->method_count(); i++) {
    307 		GenerateClientMethodSignature(service->method(i).get(), printer, vars);
    308 		printer->Print("\n");
    309 	}
    310 	printer->Outdent();
    311 	printer->Print("}\n\n");
    312 
    313 	// Client structure
    314 	vars["ServiceUnexported"] = unexportName(vars["Service"]);
    315 	printer->Print(vars, "type $ServiceUnexported$Client struct {\n");
    316 	printer->Indent();
    317 	printer->Print(vars, "cc *$grpc$.ClientConn\n");
    318 	printer->Outdent();
    319 	printer->Print("}\n\n");
    320 
    321 	// NewClient
    322 	printer->Print(vars, "func New$Service$Client(cc *$grpc$.ClientConn) $Service$Client {\n");
    323 	printer->Indent();
    324 	printer->Print(vars, "return &$ServiceUnexported$Client{cc}");
    325 	printer->Outdent();
    326 	printer->Print("\n}\n\n");
    327 
    328 	int unary_methods = 0, streaming_methods = 0;
    329 	vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc";
    330 	for (int i = 0; i < service->method_count(); i++) {
    331 		auto method = service->method(i);
    332 		if (method->NoStreaming()) {
    333 			vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]";
    334 			unary_methods++;
    335 		} else {
    336 			vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]";
    337 			streaming_methods++;
    338 		}
    339 		GenerateClientMethod(method.get(), printer, vars);
    340 	}
    341 
    342 	//Server Interface
    343 	printer->Print(vars, "// Server API for $Service$ service\n");
    344 	printer->Print(vars, "type $Service$Server interface {\n");
    345 	printer->Indent();
    346 	for (int i = 0; i < service->method_count(); i++) {
    347 		GenerateServerMethodSignature(service->method(i).get(), printer, vars);
    348 		printer->Print("\n");
    349 	}
    350 	printer->Outdent();
    351 	printer->Print("}\n\n");
    352 
    353 	// Server registration.
    354 	printer->Print(vars, "func Register$Service$Server(s *$grpc$.Server, srv $Service$Server) {\n");
    355 	printer->Indent();
    356 	printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n");
    357 	printer->Outdent();
    358 	printer->Print("}\n\n");
    359 
    360 	for (int i = 0; i < service->method_count(); i++) {
    361 		GenerateServerMethod(service->method(i).get(), printer, vars);
    362 		printer->Print("\n");
    363 	}
    364 
    365 
    366 	//Service Descriptor
    367 	printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n");
    368 	printer->Indent();
    369 	printer->Print(vars, "ServiceName: \"$Package$.$Service$\",\n");
    370 	printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n");
    371 	printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n");
    372 	printer->Indent();
    373 	for (int i = 0; i < service->method_count(); i++) {
    374 		auto method = service->method(i);
    375 		vars["Method"] = method->name();
    376 		vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
    377 		if (method->NoStreaming()) {
    378 			printer->Print("{\n");
    379 			printer->Indent();
    380 			printer->Print(vars, "MethodName: \"$Method$\",\n");
    381 			printer->Print(vars, "Handler: $Handler$, \n");
    382 			printer->Outdent();
    383 			printer->Print("},\n");
    384 		}
    385 	}
    386 	printer->Outdent();
    387 	printer->Print("},\n");
    388 	printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n");
    389 	printer->Indent();
    390 	for (int i = 0; i < service->method_count(); i++) {
    391 		auto method = service->method(i);
    392 		vars["Method"] = method->name();
    393 		vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
    394 		if (!method->NoStreaming()) {
    395 			printer->Print("{\n");
    396 			printer->Indent();
    397 			printer->Print(vars, "StreamName: \"$Method$\",\n");
    398 			printer->Print(vars, "Handler: $Handler$, \n");
    399 			if (method->ClientOnlyStreaming()) {
    400 				printer->Print("ClientStreams: true,\n");
    401 			} else if (method->ServerOnlyStreaming()) {
    402 				printer->Print("ServerStreams: true,\n");
    403 			} else {
    404 				printer->Print("ServerStreams: true,\n");
    405 				printer->Print("ClientStreams: true,\n");
    406 			}
    407 			printer->Outdent();
    408 			printer->Print("},\n");
    409 		}
    410 	}
    411 	printer->Outdent();
    412 	printer->Print("},\n");
    413 	printer->Outdent();
    414 	printer->Print("}\n\n");
    415 
    416 }
    417 
    418 
    419 // Returns source for the service
    420 grpc::string GenerateServiceSource(grpc_generator::File *file,
    421                                    const grpc_generator::Service *service,
    422                                    grpc_go_generator::Parameters *parameters) {
    423 	grpc::string out;
    424 	auto p = file->CreatePrinter(&out);
    425 	auto printer = p.get();
    426 	std::map<grpc::string, grpc::string> vars;
    427 	vars["Package"] = parameters->package_name;
    428 	vars["grpc"] = "grpc";
    429 	vars["context"] = "context";
    430 	GenerateImports(file, printer, vars);
    431 	if (parameters->custom_method_io_type != "") {
    432 		vars["CustomMethodIO"] = parameters->custom_method_io_type;
    433 	}
    434 	GenerateService(service, printer, vars);
    435 	return out;
    436 }
    437 }// Namespace grpc_go_generator
    438