blob: 922df5347ce78736fe1e9c983571a246626f343e [file] [log] [blame]
Marc Slemkob2039e72006-08-09 01:00:17 +00001import time
2import os
3import os.path
4from string import Template
5from parser import *
6from generator import *
7
8HEADER_COMMENT = """/**
9 * Autogenerated by Thrift
10 * ${date}
11 *
12 * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
13 */
14 """
15
16CPP_TYPES_HEADER = Template(HEADER_COMMENT+"""
17#if !defined(${source}_types_h_)
18#define ${source}_types_h_ 1
19
20#include <thrift/Thrift.h>
21""")
22
23CPP_TYPES_FOOTER = Template("""
24#endif // !defined(${source}_types_h_)
25""")
26
27CPP_SERVICES_HEADER = Template(HEADER_COMMENT+"""
28#if !defined(${source}_h_)
29#define ${source}_h_ 1
30
31#include <thrift/Thrift.h>
Marc Slemkodb14e172006-08-09 23:36:18 +000032#include \"${source}_types.h\"
Marc Slemkob2039e72006-08-09 01:00:17 +000033""")
34
35CPP_SERVICES_FOOTER = Template("""
36#endif // !defined(${source}_h_)""")
37
Marc Slemkodb14e172006-08-09 23:36:18 +000038CPP_IMPL_HEADER = Template(HEADER_COMMENT+"""
39#include \"${source}.h\"
40""")
41
42CPP_IMPL_FOOTER = Template("")
43
Marc Slemkob2039e72006-08-09 01:00:17 +000044def cpp_debug(arg):
45 print(arg)
46
47class Indenter(object):
48 def __init__(self, level=0, step=4):
49 self.level = level
50 self.step = step
51 self.chunk = ""
52 for i in range(step):
53 self.chunk+= " "
54 self.prefix=""
55
56 def inc(self):
57 self.level+= self.step
58 self.prefix += self.chunk
59
60 def dec(self):
61 self.level-= self.step
62 if(self.level < 0):
63 raise Exception, "Illegal indent level"
64 self.prefix = self.prefix[:self.level]
65
66 def __call__(self):
67 return self.prefix
68
69class CFile(file):
70
71 def __init__(self, name, flags):
72 file.__init__(self, name, flags)
73 self.indent = Indenter()
74 self.newline = True
75
76 def rwrite(self, value):
77 file.write(self, value)
78
79 def write(self, value=""):
80 if self.newline:
81 self.rwrite(self.indent())
82 self.newline = False
83 self.rwrite(value)
84
85 def writeln(self, value=""):
86 self.write(value+"\n")
87 self.newline = True
88
89 def beginBlock(self):
90 self.writeln("{")
91 self.indent.inc();
92
93 def endBlock(self, suffix=""):
94 self.indent.dec();
95 self.writeln("}"+suffix)
96
97CPP_PRIMITIVE_MAP = {
98 "void" : "void",
99 "bool" : "bool",
100 "string": "std::string",
101 "utf7": "std::string",
102 "utf8": "std::wstring",
103 "utf16": "std::utf16",
104 "byte" : "uint8_t",
105 "i08": "int8_t",
106 "i16": "int16_t",
107 "i32": "int32_t",
108 "i64": "int64_t",
109 "u08": "uint8_t",
110 "u16": "uint16_t",
111 "u32": "uint32_t",
112 "u64": "uint64_t",
113 "float": "double"
114}
115
116CPP_CONTAINER_MAP = {
117 Map : "std::map",
118 List: "std::list",
119 Set : "std::set",
120}
121
122def typeToCTypeDeclaration(ttype):
123
124 if isinstance(ttype, PrimitiveType):
125 return CPP_PRIMITIVE_MAP[ttype.name]
126
127 elif isinstance(ttype, CollectionType):
128
129 result = CPP_CONTAINER_MAP[type(ttype)]+"<"
130
131 if isinstance(ttype, Map):
132 result+= typeToCTypeDeclaration(ttype.keyType)+", "+ typeToCTypeDeclaration(ttype.valueType)
133
134 elif isinstance(ttype, Set) or isinstance(ttype, List):
135 result+= typeToCTypeDeclaration(ttype.valueType)
136
137 else:
138 raise Exception, "Unknown Collection Type "+str(ttype)
139
140 result+= "> "
141
142 return result
143
144 elif isinstance(ttype, Struct):
145 return "struct "+ttype.name
146
147 elif isinstance(ttype, TypeDef):
148 return ttype.name;
149
150 elif isinstance(ttype, Enum):
151 return ttype.name;
152
153 elif isinstance(ttype, Function):
154 return typeToCTypeDeclaration(ttype.resultType)+ " "+ttype.name+"("+string.join([typeToCTypeDeclaration(arg) for arg in ttype.argFieldList], ", ")+")"
155
156 elif isinstance(ttype, Field):
157 return typeToCTypeDeclaration(ttype.type)+ " "+ttype.name
158
159 else:
160 raise Exception, "Unknown type "+str(ttype)
161
162def writeTypeDefDefinition(cfile, typedef):
163
164 cfile.writeln("typedef "+typeToCTypeDeclaration(typedef.definitionType)+" "+typedef.name+";")
165
166def writeEnumDefinition(cfile, enum):
167
168 cfile.write("enum "+enum.name+" ");
169
170 cfile.beginBlock();
171
172 first = True
173
174 for ed in enum.enumDefs:
175 if first:
176 first = False
177 else:
178 cfile.writeln(",")
179 cfile.write(ed.name+" = "+str(ed.id))
180
181 cfile.writeln()
182 cfile.endBlock(";");
183
184def writeStructDefinition(cfile, struct):
185
186 cfile.write("struct "+struct.name+" ");
187
188 cfile.beginBlock()
189
190 for field in struct.fieldList:
191 cfile.writeln(typeToCTypeDeclaration(field)+";")
192
193 cfile.endBlock(";")
194
195
196CPP_DEFINITION_WRITER_MAP = {
197 TypeDef : writeTypeDefDefinition,
198 Enum : writeEnumDefinition,
199 Struct : writeStructDefinition,
200 Service : None
201 }
202
203def writeDefinitions(cfile, definitions):
204 for definition in definitions:
205
206 writer = CPP_DEFINITION_WRITER_MAP[type(definition)]
207
208 if writer:
209 writer(cfile, definition)
210
211 cfile.writeln()
212
213CPP_THRIFT_NS = "facebook::thrift"
214
215CPP_INTERFACE_FUNCTION_DECLARATION = Template(""" virtual ${functionDeclaration} = 0;
216""")
217
218CPP_INTERFACE_DECLARATION = Template("""
219class ${service}If {
220 public:
221 ~${service}If() {}
222${functionDeclarations}};
223""")
224
225def writeServiceInterfaceDeclaration(cfile, service, debugp=None):
226
227 functionDeclarations = string.join([CPP_INTERFACE_FUNCTION_DECLARATION.substitute(service=service.name, functionDeclaration=typeToCTypeDeclaration(function)) for function in service.functionList], "")
228
229 cfile.write(CPP_INTERFACE_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations))
230
231CPP_SP = Template("boost::shared_ptr<${klass}> ")
232
233CPP_PROCESSOR = CPP_THRIFT_NS+"::TProcessor"
234CPP_PROCESSORP = CPP_SP.substitute(klass=CPP_PROCESSOR)
235
236CPP_PROTOCOL_NS = CPP_THRIFT_NS+"::protocol"
237CPP_PROTOCOL = CPP_PROTOCOL_NS+"::TProcotol"
238CPP_PROTOCOLP = CPP_SP.substitute(klass=CPP_PROTOCOL)
239
240
241CPP_TRANSPORT_NS = CPP_THRIFT_NS+"::transport"
242CPP_TRANSPORT = CPP_TRANSPORT_NS+"::TTransport"
243CPP_TRANSPORTP = CPP_SP.substitute(klass=CPP_TRANSPORT)
244
245CPP_SERVER_FUNCTION_DECLARATION = Template(""" void process_${function}("""+CPP_TRANSPORTP+""" _itrans, """+CPP_TRANSPORTP+""" _otrans);
246""")
247
248CPP_PROTOCOL_TSTOP = CPP_PROTOCOL_NS+"::T_STOP"
249CPP_PROTOCOL_TTYPE = CPP_PROTOCOL_NS+"::TType"
250
Marc Slemkodb14e172006-08-09 23:36:18 +0000251CPP_TTYPE_MAP = {
252 STOP_TYPE : CPP_PROTOCOL_NS+"::T_STOP",
253 VOID_TYPE : CPP_PROTOCOL_NS+"::T_VOID",
254 BOOL_TYPE : CPP_PROTOCOL_NS+"::T_BOOL",
255 UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
256 UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
257 UTF8_TYPE : CPP_PROTOCOL_NS+"::T_UTF8",
258 UTF16_TYPE : CPP_PROTOCOL_NS+"::T_UTF16",
259 U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
260 I08_TYPE : CPP_PROTOCOL_NS+"::T_I08",
261 I16_TYPE : CPP_PROTOCOL_NS+"::T_I16",
262 I32_TYPE : CPP_PROTOCOL_NS+"::T_I32",
263 I64_TYPE : CPP_PROTOCOL_NS+"::T_I64",
264 U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
265 U16_TYPE : CPP_PROTOCOL_NS+"::T_U16",
266 U32_TYPE : CPP_PROTOCOL_NS+"::T_U32",
267 U64_TYPE : CPP_PROTOCOL_NS+"::T_U64",
268 FLOAT_TYPE : CPP_PROTOCOL_NS+"::T_FLOAT",
269 Struct : CPP_PROTOCOL_NS+"::T_STRUCT",
270 List : CPP_PROTOCOL_NS+"::T_LIST",
271 Map : CPP_PROTOCOL_NS+"::T_MAP",
272 Set : CPP_PROTOCOL_NS+"::T_SET"
273}
274
275def toWireType(ttype):
276
277 if isinstance(ttype, PrimitiveType):
278 return CPP_TTYPE_MAP[ttype]
279
280 elif isinstance(ttype, Struct) or isinstance(ttype, CollectionType):
281 return CPP_TTYPE_MAP[type(ttype)]
282
283 else:
284 raise Exception, "No wire type for thrift type: "+str(ttype)
285
Marc Slemkob2039e72006-08-09 01:00:17 +0000286CPP_SERVER_DECLARATION = Template("""
287class ${service}ServerIf : public ${service}If, public """+CPP_PROCESSOR+""" {
288 public:
289 ${service}ServerIf("""+CPP_PROTOCOLP+""" protocol): _iprot(protocol), _oprot(protocol) {}
290 ${service}ServerIf("""+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _iprot(iprot), _oprot(oprot) {}
291 virtual ~${service}ServerIf() {}
292 bool process("""+CPP_TRANSPORTP+""" _itrans,"""+CPP_TRANSPORTP+""" _otrans);
293 protected:
294 """+CPP_PROTOCOLP+""" _iprot;
295 """+CPP_PROTOCOLP+""" _oprot;
296 private:
297${functionDeclarations}};
298""")
299
300def writeServerDeclaration(cfile, service, debugp=None):
301
302 functionDeclarations = string.join([CPP_SERVER_FUNCTION_DECLARATION.substitute(function=function.name) for function in service.functionList], "")
303
304 cfile.write(CPP_SERVER_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations))
305
306CPP_CLIENT_FUNCTION_DECLARATION = Template(""" ${functionDeclaration};
307""")
308
309CPP_CLIENT_DECLARATION = Template("""
310class ${service}Client : public ${service}If {
311
312 public:
313
314 ${service}Client("""+CPP_TRANSPORTP+""" transport, """+CPP_PROTOCOLP+""" protocol): _itrans(transport), _otrans(transport), _iprot(protocol), _oprot(protocol {}
315
316 ${service}Client("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans, """+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _itrans(itrans), _otrans(otrans), _iprot(iprot), _oprot(oprot)x {}
317
318${functionDeclarations}};
319""")
320
321def writeClientDeclaration(cfile, service, debugp=None):
322
323 functionDeclarations = string.join([CPP_CLIENT_FUNCTION_DECLARATION.substitute(functionDeclaration=typeToCTypeDeclaration(function)) for function in service.functionList], "")
324
325 cfile.writeln(CPP_CLIENT_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations))
326
327def writeServiceDeclaration(cfile, service, debugp=None):
328 writeServiceInterfaceDeclaration(cfile, service, debugp)
329 writeServerDeclaration(cfile, service, debugp)
330 writeClientDeclaration(cfile, service, debugp)
331
332def toGenDir(filename, suffix="cpp-gen", debugp=None):
333
334 result = os.path.join(os.path.split(filename)[0], suffix)
335
336 if not os.path.exists(result):
337 os.mkdir(result)
338
339 return result
340
341def toBasename(filename, debugp=None):
342 """ Take the filename minus the path and\".thrift\" extension if present """
343
344 basename = os.path.split(filename)[1]
345
346 tokens = os.path.splitext(basename)
347
348 if tokens[1].lower() == ".thrift":
349 basename = tokens[0]
350
351 if debugp:
352 debugp("toBasename("+str(filename)+") => "+str(basename))
353
354 return basename
355
356def toDefinitionHeaderName(filename, genDir=None, debugp=None):
357
358 if not genDir:
359 genDir = toGenDir(filename)
360
361 basename = toBasename(filename)
362
363 result = os.path.join(genDir, basename+"_types.h")
364
365 if debugp:
366 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
367
368 return result
369
370def writeDefinitionHeader(program, filename, genDir=None, debugp=None):
371
372 definitionHeader = toDefinitionHeaderName(filename, genDir)
373
374 if debugp:
375 debugp("definitionHeader: "+str(definitionHeader))
376
377 cfile = CFile(definitionHeader, "w")
378
379 basename = toBasename(filename)
380
381 cfile.writeln(CPP_TYPES_HEADER.substitute(source=basename, date=time.ctime()))
382
383 writeDefinitions(cfile, program.definitions)
384
385 cfile.writeln(CPP_TYPES_FOOTER.substitute(source=basename))
386
387 cfile.close()
388
389def toServicesHeaderName(filename, genDir=None, debugp=None):
390
391 if not genDir:
392 genDir = toGenDir(filename)
393
394 basename = toBasename(filename)
395
396 result = os.path.join(genDir, basename+".h")
397
398 if debugp:
399 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
400
401 return result
402
403
404def writeServicesHeader(program, filename, genDir=None, debugp=None):
405
406 servicesHeader = toServicesHeaderName(filename, genDir)
407
408 if debugp:
409 debugp("servicesHeader: "+str(servicesHeader))
410
411 cfile = CFile(servicesHeader, "w")
412
413 basename = toBasename(filename)
414
415 cfile.writeln(CPP_SERVICES_HEADER.substitute(source=basename, date=time.ctime()))
416
417 services = []
418
419 # Build orderered list of service definitions by scanning definitions list for services
420
421 for definition in program.definitions:
422 if isinstance(definition, Service) and definition.name in program.serviceMap:
423 services.append(definition)
424
425 for service in services:
426
427 writeServiceDeclaration(cfile, service)
428
429 cfile.writeln(CPP_SERVICES_FOOTER.substitute(source=basename))
430
431 cfile.close()
432
433
434CPP_STRUCT_READ = Template("""void read${name}Struct("""+CPP_PROTOCOLP+""" _iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
435 std::string name;
436 uint32_t id;
437 uint32_t type;
438 while(true) {
439 _iprot->readFieldBegin(_itrans, name, type, id);
440 if(type == """+CPP_PROTOCOL_TSTOP+""") {
441 break;
442 }
443 switch(id) {
444${readFieldListSwitch}
445 }
446 }
447}
448""")
449
450CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = {
451 "bool" : "Bool",
452 "string": "String",
453 "utf7": "String",
454 "utf8": "String",
455 "utf16": "String",
456 "i08": "Byte",
457 "i16": "I16",
458 "i32": "I32",
459 "i64": "I64",
460 "u08": "Byte",
461 "u16": "U16",
462 "u32": "U32",
463 "u64": "U64",
464 "float": "Double"
465}
466
467CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP = {
Marc Slemkodb14e172006-08-09 23:36:18 +0000468 Map : "map",
469 List : "list",
470 Set : "set"
Marc Slemkob2039e72006-08-09 01:00:17 +0000471}
472
473def typeToIOMethodSuffix(ttype):
474
475 if isinstance(ttype, PrimitiveType):
476 return CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP[ttype.name]
477
478 elif isinstance(ttype, CollectionType):
479
480 result = CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP[type(ttype)]+"_"
481
482 if isinstance(ttype, Map):
483 result+= "k_"+typeToIOMethodSuffix(ttype.keyType)+"_"
484
485 result += "v_"+typeToIOMethodSuffix(ttype.valueType)
486
487 return result
488
489 elif isinstance(ttype, Struct):
490 return "struct_"+ttype.name
491
492 elif isinstance(ttype, TypeDef):
493 return typeToIOMethodSuffix(ttype.definitionType)
494
495 elif isinstance(ttype, Enum):
496 return typeToIOMethodSuffix(U32_TYPE)
497
498 else:
499 raise Exception, "Unknown type "+str(ttype)
500
Marc Slemkodb14e172006-08-09 23:36:18 +0000501def toReaderCall(value, ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000502
503 suffix = typeToIOMethodSuffix(ttype)
504
505 if isinstance(ttype, PrimitiveType):
506 return "iprot->read"+suffix+"(itrans, "+value+")"
507
508 elif isinstance(ttype, CollectionType):
509 return "read_"+suffix+"(iprot, itrans, "+value+")"
510
511 elif isinstance(ttype, Struct):
512 return "read_"+suffix+"(iprot, itrans, "+value+")"
513
514 elif isinstance(ttype, TypeDef):
Marc Slemkodb14e172006-08-09 23:36:18 +0000515 return toReaderCall(value, ttype.definitionType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000516
517 elif isinstance(ttype, Enum):
Marc Slemkodb14e172006-08-09 23:36:18 +0000518 return toReaderCall(value, U32_TYPE)
519
520 else:
521 raise Exception, "Unknown type "+str(ttype)
522
523def toWriterCall(value, ttype):
524
525 suffix = typeToIOMethodSuffix(ttype)
526
527 if isinstance(ttype, PrimitiveType):
528 return "oprot->write"+suffix+"(otrans, "+value+")"
529
530 elif isinstance(ttype, CollectionType):
531 return "write_"+suffix+"(oprot, otrans, "+value+")"
532
533 elif isinstance(ttype, Struct):
534 return "write_"+suffix+"(oprot, otrans, "+value+")"
535
536 elif isinstance(ttype, TypeDef):
537 return toWriterCall(value, ttype.definitionType)
538
539 elif isinstance(ttype, Enum):
540 return toWriterCall(value, U32_TYPE)
Marc Slemkob2039e72006-08-09 01:00:17 +0000541
542 else:
543 raise Exception, "Unknown type "+str(ttype)
544
545CPP_READ_MAP_DEFINITION = Template("""
546void read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
547
548 uint32_t count;
549 ${keyType} key;
550 ${valueType} elem;
551
Marc Slemkodb14e172006-08-09 23:36:18 +0000552 iprot->readU32(itrans, count);
Marc Slemkob2039e72006-08-09 01:00:17 +0000553
554 for(int ix = 0; ix < count; ix++) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000555 ${keyReaderCall};
556 ${valueReaderCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000557 value.insert(std::make_pair(key, elem));
558 }
559}
560""")
561
562CPP_WRITE_MAP_DEFINITION = Template("""
563void write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, ${declaration}& value) {
564
565 uint32_t count;
566 ${keyType} key;
567 ${valueType} elem;
568
Marc Slemkodb14e172006-08-09 23:36:18 +0000569 oprot->writeU32(otrans, value.size());
Marc Slemkob2039e72006-08-09 01:00:17 +0000570
Marc Slemkodb14e172006-08-09 23:36:18 +0000571 for(${declaration}::iterator ix = value.begin(); ix != value.end(); ++ix) {
572 ${keyWriterCall};
573 ${valueWriterCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000574 }
575}
576""")
577
Marc Slemkob2039e72006-08-09 01:00:17 +0000578CPP_READ_LIST_DEFINITION = Template("""
579void read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
580
581 uint32_t count;
582 ${valueType} elem;
583
Marc Slemkodb14e172006-08-09 23:36:18 +0000584 iprot->readU32(itrans, count);
Marc Slemkob2039e72006-08-09 01:00:17 +0000585
586 for(int ix = 0; ix < count; ix++) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000587 ${valueReaderCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000588 value.insert(elem);
589 }
590}
591""")
592
Marc Slemkodb14e172006-08-09 23:36:18 +0000593CPP_WRITE_LIST_DEFINITION = Template("""
594void write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, ${declaration}& value) {
595
596 uint32_t count;
597 ${valueType} elem;
598
599 oprot->writeU32(otrans, value.size());
600
601 for(${declaration}::iterator ix = value.begin(); ix != value.end(); ++ix) {
602 ${valueWriterCall};
603 }
604}
605""")
606
607def toCollectionReaderDefinition(ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000608
609 suffix = typeToIOMethodSuffix(ttype)
610
611 if isinstance(ttype, Map):
Marc Slemkodb14e172006-08-09 23:36:18 +0000612 keyReaderCall = toReaderCall("key", ttype.keyType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000613
Marc Slemkodb14e172006-08-09 23:36:18 +0000614 valueReaderCall= toReaderCall("elem", ttype.valueType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000615
616 if isinstance(ttype, Map):
617 return CPP_READ_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
618 keyType=typeToCTypeDeclaration(ttype.keyType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000619 keyReaderCall=keyReaderCall,
Marc Slemkob2039e72006-08-09 01:00:17 +0000620 valueType=typeToCTypeDeclaration(ttype.valueType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000621 valueReaderCall=valueReaderCall)
Marc Slemkob2039e72006-08-09 01:00:17 +0000622
623 else:
624 return CPP_READ_LIST_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
Marc Slemkodb14e172006-08-09 23:36:18 +0000625 valueReaderCall=valueReaderCall,
626 valueType=typeToCTypeDeclaration(ttype.valueType))
627
628
629def toCollectionWriterDefinition(ttype):
630
631 suffix = typeToIOMethodSuffix(ttype)
632
633 if isinstance(ttype, Map):
634 keyWriterCall = toWriterCall("key", ttype.keyType)
635
636 valueWriterCall= toWriterCall("elem", ttype.valueType)
637
638 if isinstance(ttype, Map):
639 return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
640 keyType=typeToCTypeDeclaration(ttype.keyType),
641 keyWriterCall=keyWriterCall,
642 valueType=typeToCTypeDeclaration(ttype.valueType),
643 valueWriterCall=valueWriterCall)
644
645 else:
646 return CPP_WRITE_LIST_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
647 valueWriterCall=valueWriterCall,
Marc Slemkob2039e72006-08-09 01:00:17 +0000648 valueType=typeToCTypeDeclaration(ttype.valueType))
649
650
651CPP_READ_STRUCT_DEFINITION = Template("""
652void read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
653
654 std::string name;
655 """+CPP_PROTOCOL_TTYPE+""" type;
656 uint16_t id;
657
658 while(true) {
659
Marc Slemkodb14e172006-08-09 23:36:18 +0000660 iprot->readFieldBegin(itrans, name, type, id);
Marc Slemkob2039e72006-08-09 01:00:17 +0000661
662 if(type == """+CPP_PROTOCOL_TSTOP+""") {break;}
663
664 switch(id) {
665${fieldSwitch}
Marc Slemkodb14e172006-08-09 23:36:18 +0000666 default:v iprot->skip(itrans, type); break;}
Marc Slemkob2039e72006-08-09 01:00:17 +0000667
Marc Slemkodb14e172006-08-09 23:36:18 +0000668 iprot->readFieldEnd(itrans);
Marc Slemkob2039e72006-08-09 01:00:17 +0000669 }
670}
671""")
672
Marc Slemkodb14e172006-08-09 23:36:18 +0000673CPP_WRITE_FIELD_DEFINITION = Template("""
674 oprot->writeFieldBegin(otrans, \"${name}\", ${type}, ${id});
675 ${fieldWriterCall};
676 oprot->writeFieldEnd(otrans);
677""")
678
679CPP_WRITE_STRUCT_DEFINITION = Template("""
680void write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
681
682 oprot->writeStructBegin(otrans, \"${name}\");
683${fieldWriterCalls}
684 oprot->writeFieldStop(otrans);
685 oprot->writeStructEnd(otrans);
686 }
687}
688""")
689
690def toStructReaderDefinition(ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000691
692 suffix = typeToIOMethodSuffix(ttype)
693
694 # Sort field list in order of increasing ids
695
696 fieldList = []
697 fieldList+= ttype.fieldList
698
699 fieldList.sort(lambda a,b: a.id - b.id)
700
701 fieldSwitch=""
702
703 for field in fieldList:
704 fieldSwitch+= " case "+str(field.id)+": "
Marc Slemkodb14e172006-08-09 23:36:18 +0000705 fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; break;\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000706
707 return CPP_READ_STRUCT_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldSwitch=fieldSwitch)
Marc Slemkodb14e172006-08-09 23:36:18 +0000708
709def toStructWriterDefinition(ttype):
710
711 suffix = typeToIOMethodSuffix(ttype)
712
713 writeCalls = ""
714
715 for field in ttype.fieldList:
716
717 writeCalls+= CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name, type=toWireType(field.type), id=field.id,
718 fieldWriterCall=toWriterCall("value."+field.name, field.type))
719
720 return CPP_WRITE_STRUCT_DEFINITION.substitute(name=ttype.name, suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldWriterCalls=writeCalls)
Marc Slemkob2039e72006-08-09 01:00:17 +0000721
Marc Slemkodb14e172006-08-09 23:36:18 +0000722def toReaderDefinition(ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000723 if isinstance(ttype, CollectionType):
Marc Slemkodb14e172006-08-09 23:36:18 +0000724 return toCollectionReaderDefinition(ttype)
Marc Slemkob2039e72006-08-09 01:00:17 +0000725
726 elif isinstance(ttype, Struct):
Marc Slemkodb14e172006-08-09 23:36:18 +0000727 return toStructReaderDefinition(ttype)
728
729def toWriterDefinition(ttype):
730 if isinstance(ttype, CollectionType):
731 return toCollectionWriterDefinition(ttype)
732
733 elif isinstance(ttype, Struct):
734 return toStructWriterDefinition(ttype)
735
736def toOrderedIOList(ttype, result=None):
737 if not result:
738 result = []
739
740 if ttype in result:
741 return result
742
743 elif isinstance(ttype, PrimitiveType):
744 return result
745
746 elif isinstance(ttype, CollectionType):
747
748 if isinstance(ttype, Map):
749 result = toOrderedIOList(ttype.keyType, result)
750
751 result = toOrderedIOList(ttype.valueType, result)
752
753 result.append(ttype)
754
755 elif isinstance(ttype, Struct):
756 for field in ttype.fieldList:
757 result = toOrderedIOList(field.type, result)
758 result.append(ttype)
759
760 elif isinstance(ttype, TypeDef):
761 return result
762
763 elif isinstance(ttype, Enum):
764 return result
765
766 elif isinstance(ttype, Program):
767
768 for struct in ttype.structMap.values():
769 result = toOrderedIOList(struct, result)
770
771 for service in ttype.serviceMap.values():
772 result = toOrderedIOList(service, result)
773
774 elif isinstance(ttype, Service):
775 for function in ttype.functionList:
776 result = toOrderedIOList(function, result)
777
778 elif isinstance(ttype, Function):
779 result = toOrderedIOList(ttype.resultType, result)
780
781 for arg in ttype.argFieldList:
782 result = toOrderedIOList(arg.type, result)
783
784 else:
785 raise Exception, "Unsupported thrift type: "+str(ttype)
786
787 return result
788
789def toIOMethodImplementations(program):
790
791 # get orderede list of all types that need marshallers:
792
793 iolist = toOrderedIOList(program)
794
795 result = ""
796
797 for ttype in iolist:
798
799 result+= toReaderDefinition(ttype)
800 result+= toWriterDefinition(ttype)
801
802 return result;
803
804def toImplementationSourceName(filename, genDir=None, debugp=None):
805
806 if not genDir:
807 genDir = toGenDir(filename)
808
809 basename = toBasename(filename)
810
811 result = os.path.join(genDir, basename+".cc")
812
813 if debugp:
814 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
815
816 return result
817
818def writeImplementationSource(program, filename, genDir=None, debugp=None):
819
820 implementationSource = toImplementationSourceName(filename, genDir)
821
822 if debugp:
823 debugp("implementationSource: "+str(implementationSource))
824
825 cfile = CFile(implementationSource, "w")
826
827 basename = toBasename(filename)
828
829 cfile.writeln(CPP_IMPL_HEADER.substitute(source=basename, date=time.ctime()))
830
831 cfile.write(toIOMethodImplementations(program))
832
833 cfile.writeln(CPP_IMPL_FOOTER.substitute(source=basename))
834
835 cfile.close()
Marc Slemkob2039e72006-08-09 01:00:17 +0000836
837class CPPGenerator(Generator):
838
839 def __call__(self, program, filename, genDir=None, debugp=None):
840
Marc Slemkodb14e172006-08-09 23:36:18 +0000841 writeDefinitionHeader(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000842
Marc Slemkodb14e172006-08-09 23:36:18 +0000843 writeServicesHeader(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000844
Marc Slemkodb14e172006-08-09 23:36:18 +0000845 writeImplementationSource(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000846