blob: f67ca00c0ba373f2b5f1bd4e26fc650ef136a1ee [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
Marc Slemkoc4eb9e82006-08-10 03:29:29 +000020#include <Thrift.h>
Marc Slemkob2039e72006-08-09 01:00:17 +000021""")
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
Marc Slemkoc4eb9e82006-08-10 03:29:29 +000031#include <Thrift.h>
32#include <TProcessor.h>
33#include <protocol/TProtocol.h>
34#include <transport/TTransport.h>
Marc Slemkodb14e172006-08-09 23:36:18 +000035#include \"${source}_types.h\"
Marc Slemkob2039e72006-08-09 01:00:17 +000036""")
37
38CPP_SERVICES_FOOTER = Template("""
39#endif // !defined(${source}_h_)""")
40
Marc Slemkodb14e172006-08-09 23:36:18 +000041CPP_IMPL_HEADER = Template(HEADER_COMMENT+"""
42#include \"${source}.h\"
43""")
44
45CPP_IMPL_FOOTER = Template("")
46
Marc Slemkob2039e72006-08-09 01:00:17 +000047def cpp_debug(arg):
48 print(arg)
49
50class Indenter(object):
51 def __init__(self, level=0, step=4):
52 self.level = level
53 self.step = step
54 self.chunk = ""
55 for i in range(step):
56 self.chunk+= " "
57 self.prefix=""
58
59 def inc(self):
60 self.level+= self.step
61 self.prefix += self.chunk
62
63 def dec(self):
64 self.level-= self.step
65 if(self.level < 0):
66 raise Exception, "Illegal indent level"
67 self.prefix = self.prefix[:self.level]
68
69 def __call__(self):
70 return self.prefix
71
72class CFile(file):
73
74 def __init__(self, name, flags):
75 file.__init__(self, name, flags)
76 self.indent = Indenter()
77 self.newline = True
78
79 def rwrite(self, value):
80 file.write(self, value)
81
82 def write(self, value=""):
83 if self.newline:
84 self.rwrite(self.indent())
85 self.newline = False
86 self.rwrite(value)
87
88 def writeln(self, value=""):
89 self.write(value+"\n")
90 self.newline = True
91
92 def beginBlock(self):
93 self.writeln("{")
94 self.indent.inc();
95
96 def endBlock(self, suffix=""):
97 self.indent.dec();
98 self.writeln("}"+suffix)
99
100CPP_PRIMITIVE_MAP = {
101 "void" : "void",
102 "bool" : "bool",
103 "string": "std::string",
104 "utf7": "std::string",
105 "utf8": "std::wstring",
106 "utf16": "std::utf16",
107 "byte" : "uint8_t",
108 "i08": "int8_t",
109 "i16": "int16_t",
110 "i32": "int32_t",
111 "i64": "int64_t",
112 "u08": "uint8_t",
113 "u16": "uint16_t",
114 "u32": "uint32_t",
115 "u64": "uint64_t",
116 "float": "double"
117}
118
119CPP_CONTAINER_MAP = {
120 Map : "std::map",
121 List: "std::list",
122 Set : "std::set",
123}
124
125def typeToCTypeDeclaration(ttype):
126
127 if isinstance(ttype, PrimitiveType):
128 return CPP_PRIMITIVE_MAP[ttype.name]
129
130 elif isinstance(ttype, CollectionType):
131
132 result = CPP_CONTAINER_MAP[type(ttype)]+"<"
133
134 if isinstance(ttype, Map):
135 result+= typeToCTypeDeclaration(ttype.keyType)+", "+ typeToCTypeDeclaration(ttype.valueType)
136
137 elif isinstance(ttype, Set) or isinstance(ttype, List):
138 result+= typeToCTypeDeclaration(ttype.valueType)
139
140 else:
141 raise Exception, "Unknown Collection Type "+str(ttype)
142
143 result+= "> "
144
145 return result
146
147 elif isinstance(ttype, Struct):
148 return "struct "+ttype.name
149
150 elif isinstance(ttype, TypeDef):
151 return ttype.name;
152
153 elif isinstance(ttype, Enum):
154 return ttype.name;
155
156 elif isinstance(ttype, Function):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000157 return typeToCTypeDeclaration(ttype.resultType)+ " "+ttype.name+"("+string.join([typeToCTypeDeclaration(arg) for arg in ttype.argsStruct.fieldList], ", ")+")"
Marc Slemkob2039e72006-08-09 01:00:17 +0000158
159 elif isinstance(ttype, Field):
160 return typeToCTypeDeclaration(ttype.type)+ " "+ttype.name
161
162 else:
163 raise Exception, "Unknown type "+str(ttype)
164
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000165def toTypeDefDefinition(typedef):
Marc Slemkob2039e72006-08-09 01:00:17 +0000166
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000167 return "typedef "+typeToCTypeDeclaration(typedef.definitionType)+" "+typedef.name+";"
Marc Slemkob2039e72006-08-09 01:00:17 +0000168
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000169def toEnumDefinition(enum):
Marc Slemkob2039e72006-08-09 01:00:17 +0000170
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000171 result = "enum "+enum.name+" {\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000172
173 first = True
174
175 for ed in enum.enumDefs:
176 if first:
177 first = False
178 else:
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000179 result+= ",\n"
180 result+= " "+ed.name+" = "+str(ed.id)
Marc Slemkob2039e72006-08-09 01:00:17 +0000181
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000182 result+= "\n};\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000183
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000184 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000185
Marc Slemkob2039e72006-08-09 01:00:17 +0000186
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000187def toStructDefinition(struct):
188
189 result = "struct "+struct.name+" {\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000190
191 for field in struct.fieldList:
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000192 result += " "+typeToCTypeDeclaration(field)+";\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000193
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000194 result+= "};\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000195
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000196 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000197
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000198CPP_DEFINITION_MAP = {
199 TypeDef : toTypeDefDefinition,
200 Enum : toEnumDefinition,
201 Struct : toStructDefinition,
Marc Slemkob2039e72006-08-09 01:00:17 +0000202 Service : None
203 }
204
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000205def toDefinitions(definitions):
206
207 result = ""
208
Marc Slemkob2039e72006-08-09 01:00:17 +0000209 for definition in definitions:
210
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000211 writer = CPP_DEFINITION_MAP[type(definition)]
Marc Slemkob2039e72006-08-09 01:00:17 +0000212
213 if writer:
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000214 result+= writer(definition)+"\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000215
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000216 return result
Marc Slemkob2039e72006-08-09 01:00:17 +0000217
218CPP_THRIFT_NS = "facebook::thrift"
219
220CPP_INTERFACE_FUNCTION_DECLARATION = Template(""" virtual ${functionDeclaration} = 0;
221""")
222
223CPP_INTERFACE_DECLARATION = Template("""
224class ${service}If {
225 public:
226 ~${service}If() {}
227${functionDeclarations}};
228""")
229
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000230def toServiceInterfaceDeclaration(service, debugp=None):
Marc Slemkob2039e72006-08-09 01:00:17 +0000231
232 functionDeclarations = string.join([CPP_INTERFACE_FUNCTION_DECLARATION.substitute(service=service.name, functionDeclaration=typeToCTypeDeclaration(function)) for function in service.functionList], "")
233
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000234 return CPP_INTERFACE_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)
Marc Slemkob2039e72006-08-09 01:00:17 +0000235
236CPP_SP = Template("boost::shared_ptr<${klass}> ")
237
238CPP_PROCESSOR = CPP_THRIFT_NS+"::TProcessor"
239CPP_PROCESSORP = CPP_SP.substitute(klass=CPP_PROCESSOR)
240
241CPP_PROTOCOL_NS = CPP_THRIFT_NS+"::protocol"
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000242CPP_PROTOCOL = CPP_PROTOCOL_NS+"::TProtocol"
243CPP_PROTOCOLP = CPP_SP.substitute(klass="const "+CPP_PROTOCOL)
Marc Slemkob2039e72006-08-09 01:00:17 +0000244
245
246CPP_TRANSPORT_NS = CPP_THRIFT_NS+"::transport"
247CPP_TRANSPORT = CPP_TRANSPORT_NS+"::TTransport"
248CPP_TRANSPORTP = CPP_SP.substitute(klass=CPP_TRANSPORT)
249
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000250CPP_SERVER_FUNCTION_DECLARATION = Template(""" void process_${function}("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans);
251""")
252
253CPP_SERVER_FUNCTION_DEFINITION = Template("""
254void ${service}ServerIf::process_${function}("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans) {
255
256 uint32_t xfer = 0;
257
258${argsStructDeclaration}
259${argsStructReader}
260${resultDeclaration}
261${functionCall}
262${resultWriter}
263
264 otrans->flush();
265}
Marc Slemkob2039e72006-08-09 01:00:17 +0000266""")
267
268CPP_PROTOCOL_TSTOP = CPP_PROTOCOL_NS+"::T_STOP"
269CPP_PROTOCOL_TTYPE = CPP_PROTOCOL_NS+"::TType"
270
Marc Slemkodb14e172006-08-09 23:36:18 +0000271CPP_TTYPE_MAP = {
272 STOP_TYPE : CPP_PROTOCOL_NS+"::T_STOP",
273 VOID_TYPE : CPP_PROTOCOL_NS+"::T_VOID",
274 BOOL_TYPE : CPP_PROTOCOL_NS+"::T_BOOL",
275 UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
276 UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
277 UTF8_TYPE : CPP_PROTOCOL_NS+"::T_UTF8",
278 UTF16_TYPE : CPP_PROTOCOL_NS+"::T_UTF16",
279 U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
280 I08_TYPE : CPP_PROTOCOL_NS+"::T_I08",
281 I16_TYPE : CPP_PROTOCOL_NS+"::T_I16",
282 I32_TYPE : CPP_PROTOCOL_NS+"::T_I32",
283 I64_TYPE : CPP_PROTOCOL_NS+"::T_I64",
284 U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
285 U16_TYPE : CPP_PROTOCOL_NS+"::T_U16",
286 U32_TYPE : CPP_PROTOCOL_NS+"::T_U32",
287 U64_TYPE : CPP_PROTOCOL_NS+"::T_U64",
288 FLOAT_TYPE : CPP_PROTOCOL_NS+"::T_FLOAT",
289 Struct : CPP_PROTOCOL_NS+"::T_STRUCT",
290 List : CPP_PROTOCOL_NS+"::T_LIST",
291 Map : CPP_PROTOCOL_NS+"::T_MAP",
292 Set : CPP_PROTOCOL_NS+"::T_SET"
293}
294
295def toWireType(ttype):
296
297 if isinstance(ttype, PrimitiveType):
298 return CPP_TTYPE_MAP[ttype]
299
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000300 elif isinstance(ttype, Enum):
301 return CPP_TTYPE_MAP[I32_TYPE]
302
303 elif isinstance(ttype, TypeDef):
304 return toWireType(toCanonicalType(ttype))
305
Marc Slemkodb14e172006-08-09 23:36:18 +0000306 elif isinstance(ttype, Struct) or isinstance(ttype, CollectionType):
307 return CPP_TTYPE_MAP[type(ttype)]
308
309 else:
310 raise Exception, "No wire type for thrift type: "+str(ttype)
311
Marc Slemkob2039e72006-08-09 01:00:17 +0000312CPP_SERVER_DECLARATION = Template("""
313class ${service}ServerIf : public ${service}If, public """+CPP_PROCESSOR+""" {
314 public:
315 ${service}ServerIf("""+CPP_PROTOCOLP+""" protocol): _iprot(protocol), _oprot(protocol) {}
316 ${service}ServerIf("""+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _iprot(iprot), _oprot(oprot) {}
317 virtual ~${service}ServerIf() {}
318 bool process("""+CPP_TRANSPORTP+""" _itrans,"""+CPP_TRANSPORTP+""" _otrans);
319 protected:
320 """+CPP_PROTOCOLP+""" _iprot;
321 """+CPP_PROTOCOLP+""" _oprot;
322 private:
323${functionDeclarations}};
324""")
325
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000326def toServerDeclaration(service, debugp=None):
Marc Slemkob2039e72006-08-09 01:00:17 +0000327
328 functionDeclarations = string.join([CPP_SERVER_FUNCTION_DECLARATION.substitute(function=function.name) for function in service.functionList], "")
329
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000330 return CPP_SERVER_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)
Marc Slemkob2039e72006-08-09 01:00:17 +0000331
332CPP_CLIENT_FUNCTION_DECLARATION = Template(""" ${functionDeclaration};
333""")
334
335CPP_CLIENT_DECLARATION = Template("""
336class ${service}Client : public ${service}If {
337
338 public:
339
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000340 ${service}Client("""+CPP_TRANSPORTP+""" transport, """+CPP_PROTOCOLP+""" protocol): _itrans(transport), _otrans(transport), _iprot(protocol), _oprot(protocol) {}
Marc Slemkob2039e72006-08-09 01:00:17 +0000341
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000342 ${service}Client("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans, """+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _itrans(itrans), _otrans(otrans), _iprot(iprot), _oprot(oprot) {}
Marc Slemkob2039e72006-08-09 01:00:17 +0000343
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000344${functionDeclarations}
345 private:
346 """+CPP_TRANSPORTP+""" _itrans;
347 """+CPP_TRANSPORTP+""" _otrans;
348 """+CPP_PROTOCOLP+""" _iprot;
349 """+CPP_PROTOCOLP+""" _oprot;
350};""")
Marc Slemkob2039e72006-08-09 01:00:17 +0000351
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000352def toServerServiceDefinition(service, debugp=None):
353
354 result = ""
355
356 for function in service.functionList:
357
358 if len(function.argsStruct.fieldList) > 0:
359 argsStructDeclaration = " "+typeToCTypeDeclaration(function.argsStruct)+" __args;\n"
360 argsStructReader = " "+toReaderCall("__args", function.argsStruct, "_iprot")+";\n"
361 else:
362 argsStructDeclaration = ""
363 argsStructReader = ""
364
365 functionCall = " "
366 resultDeclaration = ""
367 resultWriter = ""
368
369 if toCanonicalType(function.resultType) != VOID_TYPE:
370 resultDeclaration = " "+typeToCTypeDeclaration(function.resultType)+" __result;\n"
371 functionCall+= "__result = "
372
373 functionCall+= function.name+"("+string.join(["__args."+arg.name for arg in function.argsStruct.fieldList], ", ")+");\n"
374
375 if toCanonicalType(function.resultType) != VOID_TYPE:
376 resultWriter = " "+toWriterCall("__result", function.resultType, "_oprot")+";"
377
378 result+= CPP_SERVER_FUNCTION_DEFINITION.substitute(service=service.name, function=function.name,
379 argsStructDeclaration=argsStructDeclaration, argsStructReader=argsStructReader,
380 functionCall=functionCall,
381 resultDeclaration=resultDeclaration, resultWriter=resultWriter)
382
383 return result
384
385def toServerDefinition(program, debugp=None):
386
387 return string.join([toServerServiceDefinition(service) for service in program.serviceMap.values()], "\n")
388
389def toClientDeclaration(service, debugp=None):
Marc Slemkob2039e72006-08-09 01:00:17 +0000390
391 functionDeclarations = string.join([CPP_CLIENT_FUNCTION_DECLARATION.substitute(functionDeclaration=typeToCTypeDeclaration(function)) for function in service.functionList], "")
392
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000393 return CPP_CLIENT_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)+"\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000394
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000395def toServiceDeclaration(service, debugp=None):
396 return toServiceInterfaceDeclaration(service, debugp) + toServerDeclaration(service, debugp) + toClientDeclaration(service, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000397
398def toGenDir(filename, suffix="cpp-gen", debugp=None):
399
400 result = os.path.join(os.path.split(filename)[0], suffix)
401
402 if not os.path.exists(result):
403 os.mkdir(result)
404
405 return result
406
407def toBasename(filename, debugp=None):
408 """ Take the filename minus the path and\".thrift\" extension if present """
409
410 basename = os.path.split(filename)[1]
411
412 tokens = os.path.splitext(basename)
413
414 if tokens[1].lower() == ".thrift":
415 basename = tokens[0]
416
417 if debugp:
418 debugp("toBasename("+str(filename)+") => "+str(basename))
419
420 return basename
421
422def toDefinitionHeaderName(filename, genDir=None, debugp=None):
423
424 if not genDir:
425 genDir = toGenDir(filename)
426
427 basename = toBasename(filename)
428
429 result = os.path.join(genDir, basename+"_types.h")
430
431 if debugp:
432 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
433
434 return result
435
436def writeDefinitionHeader(program, filename, genDir=None, debugp=None):
437
438 definitionHeader = toDefinitionHeaderName(filename, genDir)
439
440 if debugp:
441 debugp("definitionHeader: "+str(definitionHeader))
442
443 cfile = CFile(definitionHeader, "w")
444
445 basename = toBasename(filename)
446
447 cfile.writeln(CPP_TYPES_HEADER.substitute(source=basename, date=time.ctime()))
448
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000449 cfile.write(toDefinitions(program.definitions))
Marc Slemkob2039e72006-08-09 01:00:17 +0000450
451 cfile.writeln(CPP_TYPES_FOOTER.substitute(source=basename))
452
453 cfile.close()
454
455def toServicesHeaderName(filename, genDir=None, debugp=None):
456
457 if not genDir:
458 genDir = toGenDir(filename)
459
460 basename = toBasename(filename)
461
462 result = os.path.join(genDir, basename+".h")
463
464 if debugp:
465 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
466
467 return result
468
469
470def writeServicesHeader(program, filename, genDir=None, debugp=None):
471
472 servicesHeader = toServicesHeaderName(filename, genDir)
473
474 if debugp:
475 debugp("servicesHeader: "+str(servicesHeader))
476
477 cfile = CFile(servicesHeader, "w")
478
479 basename = toBasename(filename)
480
481 cfile.writeln(CPP_SERVICES_HEADER.substitute(source=basename, date=time.ctime()))
482
483 services = []
484
485 # Build orderered list of service definitions by scanning definitions list for services
486
487 for definition in program.definitions:
488 if isinstance(definition, Service) and definition.name in program.serviceMap:
489 services.append(definition)
490
491 for service in services:
492
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000493 cfile.write(toServiceDeclaration(service))
Marc Slemkob2039e72006-08-09 01:00:17 +0000494
495 cfile.writeln(CPP_SERVICES_FOOTER.substitute(source=basename))
496
497 cfile.close()
498
499
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000500CPP_STRUCT_READ = Template("""
501uint32_t read${name}Struct("""+CPP_PROTOCOLP+""" _iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
502
Marc Slemkob2039e72006-08-09 01:00:17 +0000503 std::string name;
504 uint32_t id;
505 uint32_t type;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000506 uint32_t xfer = 0;
507
Marc Slemkob2039e72006-08-09 01:00:17 +0000508 while(true) {
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000509 xfer+= _iprot->readFieldBegin(_itrans, name, type, id);
Marc Slemkob2039e72006-08-09 01:00:17 +0000510 if(type == """+CPP_PROTOCOL_TSTOP+""") {
511 break;
512 }
513 switch(id) {
514${readFieldListSwitch}
515 }
516 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000517
518 xfer+= _iprot->readStructEnd(_itrans);
519
520 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000521}
522""")
523
524CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = {
525 "bool" : "Bool",
526 "string": "String",
527 "utf7": "String",
528 "utf8": "String",
529 "utf16": "String",
530 "i08": "Byte",
531 "i16": "I16",
532 "i32": "I32",
533 "i64": "I64",
534 "u08": "Byte",
535 "u16": "U16",
536 "u32": "U32",
537 "u64": "U64",
538 "float": "Double"
539}
540
541CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP = {
Marc Slemkodb14e172006-08-09 23:36:18 +0000542 Map : "map",
543 List : "list",
544 Set : "set"
Marc Slemkob2039e72006-08-09 01:00:17 +0000545}
546
547def typeToIOMethodSuffix(ttype):
548
549 if isinstance(ttype, PrimitiveType):
550 return CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP[ttype.name]
551
552 elif isinstance(ttype, CollectionType):
553
554 result = CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP[type(ttype)]+"_"
555
556 if isinstance(ttype, Map):
557 result+= "k_"+typeToIOMethodSuffix(ttype.keyType)+"_"
558
559 result += "v_"+typeToIOMethodSuffix(ttype.valueType)
560
561 return result
562
563 elif isinstance(ttype, Struct):
564 return "struct_"+ttype.name
565
566 elif isinstance(ttype, TypeDef):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000567 return ttype.name
Marc Slemkob2039e72006-08-09 01:00:17 +0000568
569 elif isinstance(ttype, Enum):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000570 return ttype.name
Marc Slemkob2039e72006-08-09 01:00:17 +0000571
572 else:
573 raise Exception, "Unknown type "+str(ttype)
574
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000575def toReaderCall(value, ttype, reader="iprot"):
Marc Slemkob2039e72006-08-09 01:00:17 +0000576
577 suffix = typeToIOMethodSuffix(ttype)
578
579 if isinstance(ttype, PrimitiveType):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000580 return "xfer += "+reader+"->read"+suffix+"(itrans, "+value+")"
Marc Slemkob2039e72006-08-09 01:00:17 +0000581
582 elif isinstance(ttype, CollectionType):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000583 return "xfer+= read_"+suffix+"("+reader+", itrans, "+value+")"
Marc Slemkob2039e72006-08-09 01:00:17 +0000584
585 elif isinstance(ttype, Struct):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000586 return "xfer+= read_"+suffix+"("+reader+", itrans, "+value+")"
Marc Slemkob2039e72006-08-09 01:00:17 +0000587
588 elif isinstance(ttype, TypeDef):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000589 return toReaderCall("reinterpret_cast<"+typeToCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, reader)
Marc Slemkob2039e72006-08-09 01:00:17 +0000590
591 elif isinstance(ttype, Enum):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000592 return toReaderCall("reinterpret_cast<"+typeToCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, reader)
Marc Slemkodb14e172006-08-09 23:36:18 +0000593
594 else:
595 raise Exception, "Unknown type "+str(ttype)
596
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000597def toWriterCall(value, ttype, writer="oprot"):
Marc Slemkodb14e172006-08-09 23:36:18 +0000598
599 suffix = typeToIOMethodSuffix(ttype)
600
601 if isinstance(ttype, PrimitiveType):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000602 return "xfer+= "+writer+"->write"+suffix+"(otrans, "+value+")"
Marc Slemkodb14e172006-08-09 23:36:18 +0000603
604 elif isinstance(ttype, CollectionType):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000605 return "xfer+= write_"+suffix+"("+writer+", otrans, "+value+")"
Marc Slemkodb14e172006-08-09 23:36:18 +0000606
607 elif isinstance(ttype, Struct):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000608 return "xfer+= write_"+suffix+"("+writer+", otrans, "+value+")"
Marc Slemkodb14e172006-08-09 23:36:18 +0000609
610 elif isinstance(ttype, TypeDef):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000611 return toWriterCall("reinterpret_cast<const "+typeToCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, writer)
Marc Slemkodb14e172006-08-09 23:36:18 +0000612
613 elif isinstance(ttype, Enum):
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000614 return toWriterCall("reinterpret_cast<const "+typeToCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, writer)
Marc Slemkob2039e72006-08-09 01:00:17 +0000615
616 else:
617 raise Exception, "Unknown type "+str(ttype)
618
619CPP_READ_MAP_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000620uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000621
622 uint32_t count;
623 ${keyType} key;
624 ${valueType} elem;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000625 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000626
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000627 xfer += iprot->readU32(itrans, count);
Marc Slemkob2039e72006-08-09 01:00:17 +0000628
629 for(int ix = 0; ix < count; ix++) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000630 ${keyReaderCall};
631 ${valueReaderCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000632 value.insert(std::make_pair(key, elem));
633 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000634
635 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000636}
637""")
638
639CPP_WRITE_MAP_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000640uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000641
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000642 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000643
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000644 xfer += oprot->writeU32(otrans, value.size());
Marc Slemkob2039e72006-08-09 01:00:17 +0000645
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000646 for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000647 ${keyWriterCall};
648 ${valueWriterCall};
Marc Slemkob2039e72006-08-09 01:00:17 +0000649 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000650 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000651}
652""")
653
Marc Slemkob2039e72006-08-09 01:00:17 +0000654CPP_READ_LIST_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000655uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000656
657 uint32_t count;
658 ${valueType} elem;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000659 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000660
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000661 xfer+= iprot->readU32(itrans, count);
Marc Slemkob2039e72006-08-09 01:00:17 +0000662
663 for(int ix = 0; ix < count; ix++) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000664 ${valueReaderCall};
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000665 value.${insert}(elem);
Marc Slemkob2039e72006-08-09 01:00:17 +0000666 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000667 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000668}
669""")
670
Marc Slemkodb14e172006-08-09 23:36:18 +0000671CPP_WRITE_LIST_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000672uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000673
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000674 uint32_t xfer = 0;
Marc Slemkodb14e172006-08-09 23:36:18 +0000675
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000676 xfer+= oprot->writeU32(otrans, value.size());
Marc Slemkodb14e172006-08-09 23:36:18 +0000677
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000678 for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000679 ${valueWriterCall};
680 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000681 return xfer;
Marc Slemkodb14e172006-08-09 23:36:18 +0000682}
683""")
684
685def toCollectionReaderDefinition(ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000686
687 suffix = typeToIOMethodSuffix(ttype)
688
689 if isinstance(ttype, Map):
Marc Slemkodb14e172006-08-09 23:36:18 +0000690 keyReaderCall = toReaderCall("key", ttype.keyType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000691
Marc Slemkodb14e172006-08-09 23:36:18 +0000692 valueReaderCall= toReaderCall("elem", ttype.valueType)
Marc Slemkob2039e72006-08-09 01:00:17 +0000693
694 if isinstance(ttype, Map):
695 return CPP_READ_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
696 keyType=typeToCTypeDeclaration(ttype.keyType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000697 keyReaderCall=keyReaderCall,
Marc Slemkob2039e72006-08-09 01:00:17 +0000698 valueType=typeToCTypeDeclaration(ttype.valueType),
Marc Slemkodb14e172006-08-09 23:36:18 +0000699 valueReaderCall=valueReaderCall)
Marc Slemkob2039e72006-08-09 01:00:17 +0000700
701 else:
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000702 if isinstance(ttype, List):
703 insert="push_back"
704 else:
705 insert="insert"
706
Marc Slemkob2039e72006-08-09 01:00:17 +0000707 return CPP_READ_LIST_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
Marc Slemkodb14e172006-08-09 23:36:18 +0000708 valueReaderCall=valueReaderCall,
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000709 valueType=typeToCTypeDeclaration(ttype.valueType),
710 insert=insert)
Marc Slemkodb14e172006-08-09 23:36:18 +0000711
712
713def toCollectionWriterDefinition(ttype):
714
715 suffix = typeToIOMethodSuffix(ttype)
716
717 if isinstance(ttype, Map):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000718 keyWriterCall = toWriterCall("ix->first", ttype.keyType)
719 valueWriterCall = toWriterCall("ix->second", ttype.valueType)
Marc Slemkodb14e172006-08-09 23:36:18 +0000720
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000721 else:
722 valueWriterCall= toWriterCall("*ix", ttype.valueType)
Marc Slemkodb14e172006-08-09 23:36:18 +0000723
724 if isinstance(ttype, Map):
725 return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
726 keyType=typeToCTypeDeclaration(ttype.keyType),
727 keyWriterCall=keyWriterCall,
728 valueType=typeToCTypeDeclaration(ttype.valueType),
729 valueWriterCall=valueWriterCall)
730
731 else:
732 return CPP_WRITE_LIST_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
733 valueWriterCall=valueWriterCall,
Marc Slemkob2039e72006-08-09 01:00:17 +0000734 valueType=typeToCTypeDeclaration(ttype.valueType))
735
736
737CPP_READ_STRUCT_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000738uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
Marc Slemkob2039e72006-08-09 01:00:17 +0000739
740 std::string name;
741 """+CPP_PROTOCOL_TTYPE+""" type;
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000742 int16_t id;
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000743 uint32_t xfer = 0;
Marc Slemkob2039e72006-08-09 01:00:17 +0000744
745 while(true) {
746
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000747 xfer+= iprot->readFieldBegin(itrans, name, type, id);
Marc Slemkob2039e72006-08-09 01:00:17 +0000748
749 if(type == """+CPP_PROTOCOL_TSTOP+""") {break;}
750
751 switch(id) {
752${fieldSwitch}
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000753 default: xfer += iprot->skip(itrans, type); break;}
Marc Slemkob2039e72006-08-09 01:00:17 +0000754
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000755 xfer+= iprot->readFieldEnd(itrans);
Marc Slemkob2039e72006-08-09 01:00:17 +0000756 }
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000757 return xfer;
Marc Slemkob2039e72006-08-09 01:00:17 +0000758}
759""")
760
Marc Slemkodb14e172006-08-09 23:36:18 +0000761CPP_WRITE_FIELD_DEFINITION = Template("""
762 oprot->writeFieldBegin(otrans, \"${name}\", ${type}, ${id});
763 ${fieldWriterCall};
764 oprot->writeFieldEnd(otrans);
765""")
766
767CPP_WRITE_STRUCT_DEFINITION = Template("""
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000768uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
Marc Slemkodb14e172006-08-09 23:36:18 +0000769
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000770 uint32_t xfer = 0;
771
772 xfer+= oprot->writeStructBegin(otrans, \"${name}\");
Marc Slemkodb14e172006-08-09 23:36:18 +0000773${fieldWriterCalls}
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000774 xfer+= oprot->writeFieldStop(otrans);
775 xfer += oprot->writeStructEnd(otrans);
776 return xfer;
Marc Slemkodb14e172006-08-09 23:36:18 +0000777}
778""")
779
780def toStructReaderDefinition(ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000781
782 suffix = typeToIOMethodSuffix(ttype)
783
784 # Sort field list in order of increasing ids
785
786 fieldList = []
787 fieldList+= ttype.fieldList
788
789 fieldList.sort(lambda a,b: a.id - b.id)
790
791 fieldSwitch=""
792
793 for field in fieldList:
794 fieldSwitch+= " case "+str(field.id)+": "
Marc Slemkodb14e172006-08-09 23:36:18 +0000795 fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; break;\n"
Marc Slemkob2039e72006-08-09 01:00:17 +0000796
797 return CPP_READ_STRUCT_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldSwitch=fieldSwitch)
Marc Slemkodb14e172006-08-09 23:36:18 +0000798
799def toStructWriterDefinition(ttype):
800
801 suffix = typeToIOMethodSuffix(ttype)
802
803 writeCalls = ""
804
805 for field in ttype.fieldList:
806
807 writeCalls+= CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name, type=toWireType(field.type), id=field.id,
808 fieldWriterCall=toWriterCall("value."+field.name, field.type))
809
810 return CPP_WRITE_STRUCT_DEFINITION.substitute(name=ttype.name, suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldWriterCalls=writeCalls)
Marc Slemkob2039e72006-08-09 01:00:17 +0000811
Marc Slemkodb14e172006-08-09 23:36:18 +0000812def toReaderDefinition(ttype):
Marc Slemkob2039e72006-08-09 01:00:17 +0000813 if isinstance(ttype, CollectionType):
Marc Slemkodb14e172006-08-09 23:36:18 +0000814 return toCollectionReaderDefinition(ttype)
Marc Slemkob2039e72006-08-09 01:00:17 +0000815
816 elif isinstance(ttype, Struct):
Marc Slemkodb14e172006-08-09 23:36:18 +0000817 return toStructReaderDefinition(ttype)
818
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000819 elif isinstance(ttype, TypeDef):
820 return ""
821
822 elif isinstance(ttype, Enum):
823 return ""
824
825 else:
826 raise Exception, "Unsupported type: "+str(ttype)
827
Marc Slemkodb14e172006-08-09 23:36:18 +0000828def toWriterDefinition(ttype):
829 if isinstance(ttype, CollectionType):
830 return toCollectionWriterDefinition(ttype)
831
832 elif isinstance(ttype, Struct):
833 return toStructWriterDefinition(ttype)
834
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000835 elif isinstance(ttype, TypeDef):
836 return ""
837
838 elif isinstance(ttype, Enum):
839 return ""
840
841 else:
842 raise Exception, "Unsupported type: "+str(ttype)
843
Marc Slemkodb14e172006-08-09 23:36:18 +0000844def toOrderedIOList(ttype, result=None):
845 if not result:
846 result = []
847
848 if ttype in result:
849 return result
850
851 elif isinstance(ttype, PrimitiveType):
852 return result
853
854 elif isinstance(ttype, CollectionType):
855
856 if isinstance(ttype, Map):
857 result = toOrderedIOList(ttype.keyType, result)
858
859 result = toOrderedIOList(ttype.valueType, result)
860
861 result.append(ttype)
862
863 elif isinstance(ttype, Struct):
864 for field in ttype.fieldList:
865 result = toOrderedIOList(field.type, result)
866 result.append(ttype)
867
868 elif isinstance(ttype, TypeDef):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000869 result.append(ttype)
Marc Slemkodb14e172006-08-09 23:36:18 +0000870 return result
871
872 elif isinstance(ttype, Enum):
Marc Slemkoc4eb9e82006-08-10 03:29:29 +0000873 result.append(ttype)
Marc Slemkodb14e172006-08-09 23:36:18 +0000874 return result
875
876 elif isinstance(ttype, Program):
877
878 for struct in ttype.structMap.values():
879 result = toOrderedIOList(struct, result)
880
881 for service in ttype.serviceMap.values():
882 result = toOrderedIOList(service, result)
883
884 elif isinstance(ttype, Service):
885 for function in ttype.functionList:
886 result = toOrderedIOList(function, result)
887
888 elif isinstance(ttype, Function):
889 result = toOrderedIOList(ttype.resultType, result)
890
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000891 # skip the args struct itself and just order the arguments themselves
892 # we don't want the arg struct to be referred to until laters, since we need to
893 # inline those struct definitions with the implementation, not in the types header
894
895 for field in ttype.argsStruct.fieldList:
896 result = toOrderedIOList(field.type, result)
Marc Slemkodb14e172006-08-09 23:36:18 +0000897
898 else:
899 raise Exception, "Unsupported thrift type: "+str(ttype)
900
901 return result
902
903def toIOMethodImplementations(program):
904
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000905 # get ordered list of all types that need marshallers:
Marc Slemkodb14e172006-08-09 23:36:18 +0000906
907 iolist = toOrderedIOList(program)
908
909 result = ""
910
911 for ttype in iolist:
Marc Slemkodb14e172006-08-09 23:36:18 +0000912 result+= toReaderDefinition(ttype)
913 result+= toWriterDefinition(ttype)
914
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000915 # for all function argument lists we need to create both struct definitions
916 # and io methods. We keep the struct definitions local, since they aren't part of the service
917 # API
918 # Note that we don't need to do a depth-first traverse of arg structs since they can only include fields
919 # we've already seen
920
921 for service in program.serviceMap.values():
922 for function in service.functionList:
923 if len(function.argsStruct.fieldList) == 0:
924 continue
925 result+= toStructDefinition(function.argsStruct)
926 result+=toReaderDefinition(function.argsStruct)
927 result+=toWriterDefinition(function.argsStruct)
928
Marc Slemkodb14e172006-08-09 23:36:18 +0000929 return result;
930
931def toImplementationSourceName(filename, genDir=None, debugp=None):
932
933 if not genDir:
934 genDir = toGenDir(filename)
935
936 basename = toBasename(filename)
937
938 result = os.path.join(genDir, basename+".cc")
939
940 if debugp:
941 debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
942
943 return result
944
945def writeImplementationSource(program, filename, genDir=None, debugp=None):
946
947 implementationSource = toImplementationSourceName(filename, genDir)
948
949 if debugp:
950 debugp("implementationSource: "+str(implementationSource))
951
952 cfile = CFile(implementationSource, "w")
953
954 basename = toBasename(filename)
955
956 cfile.writeln(CPP_IMPL_HEADER.substitute(source=basename, date=time.ctime()))
957
958 cfile.write(toIOMethodImplementations(program))
959
Marc Slemko0b4ffa92006-08-11 02:49:29 +0000960 cfile.write(toServerDefinition(program))
961
Marc Slemkodb14e172006-08-09 23:36:18 +0000962 cfile.writeln(CPP_IMPL_FOOTER.substitute(source=basename))
963
964 cfile.close()
Marc Slemkob2039e72006-08-09 01:00:17 +0000965
966class CPPGenerator(Generator):
967
968 def __call__(self, program, filename, genDir=None, debugp=None):
969
Marc Slemkodb14e172006-08-09 23:36:18 +0000970 writeDefinitionHeader(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000971
Marc Slemkodb14e172006-08-09 23:36:18 +0000972 writeServicesHeader(program, filename, genDir, debugp)
Marc Slemkob2039e72006-08-09 01:00:17 +0000973
Marc Slemkodb14e172006-08-09 23:36:18 +0000974 writeImplementationSource(program, filename, genDir, debugp)