blob: 834877ef8c19c97fb74b529c30712f27ae3aa793 [file] [log] [blame]
import time
import os
import os.path
from string import Template
from parser import *
from generator import *
HEADER_COMMENT = """/**
* Autogenerated by Thrift
* ${date}
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
*/
"""
CPP_TYPES_HEADER = Template(HEADER_COMMENT+"""
#if !defined(${source}_types_h_)
#define ${source}_types_h_ 1
#include <Thrift.h>
""")
CPP_TYPES_FOOTER = Template("""
#endif // !defined(${source}_types_h_)
""")
CPP_SERVICES_HEADER = Template(HEADER_COMMENT+"""
#if !defined(${source}_h_)
#define ${source}_h_ 1
#include <Thrift.h>
#include <TProcessor.h>
#include <protocol/TProtocol.h>
#include <transport/TTransport.h>
#include \"${source}_types.h\"
""")
CPP_SERVICES_FOOTER = Template("""
#endif // !defined(${source}_h_)""")
CPP_IMPL_HEADER = Template(HEADER_COMMENT+"""
#include \"${source}.h\"
""")
CPP_IMPL_FOOTER = Template("")
def cpp_debug(arg):
print(arg)
class Indenter(object):
def __init__(self, level=0, step=4):
self.level = level
self.step = step
self.chunk = ""
for i in range(step):
self.chunk+= " "
self.prefix=""
def inc(self):
self.level+= self.step
self.prefix += self.chunk
def dec(self):
self.level-= self.step
if(self.level < 0):
raise Exception, "Illegal indent level"
self.prefix = self.prefix[:self.level]
def __call__(self):
return self.prefix
class CFile(file):
def __init__(self, name, flags):
file.__init__(self, name, flags)
self.indent = Indenter()
self.newline = True
def rwrite(self, value):
file.write(self, value)
def write(self, value=""):
if self.newline:
self.rwrite(self.indent())
self.newline = False
self.rwrite(value)
def writeln(self, value=""):
self.write(value+"\n")
self.newline = True
def beginBlock(self):
self.writeln("{")
self.indent.inc();
def endBlock(self, suffix=""):
self.indent.dec();
self.writeln("}"+suffix)
CPP_PRIMITIVE_MAP = {
"void" : "void",
"bool" : "bool",
"string": "std::string",
"utf7": "std::string",
"utf8": "std::wstring",
"utf16": "std::utf16",
"byte" : "uint8_t",
"i08": "int8_t",
"i16": "int16_t",
"i32": "int32_t",
"i64": "int64_t",
"u08": "uint8_t",
"u16": "uint16_t",
"u32": "uint32_t",
"u64": "uint64_t",
"float": "double"
}
CPP_CONTAINER_MAP = {
Map : "std::map",
List: "std::list",
Set : "std::set",
}
def typeToCTypeDeclaration(ttype):
if isinstance(ttype, PrimitiveType):
return CPP_PRIMITIVE_MAP[ttype.name]
elif isinstance(ttype, CollectionType):
result = CPP_CONTAINER_MAP[type(ttype)]+"<"
if isinstance(ttype, Map):
result+= typeToCTypeDeclaration(ttype.keyType)+", "+ typeToCTypeDeclaration(ttype.valueType)
elif isinstance(ttype, Set) or isinstance(ttype, List):
result+= typeToCTypeDeclaration(ttype.valueType)
else:
raise Exception, "Unknown Collection Type "+str(ttype)
result+= "> "
return result
elif isinstance(ttype, Struct):
return "struct "+ttype.name
elif isinstance(ttype, TypeDef):
return ttype.name;
elif isinstance(ttype, Enum):
return ttype.name;
elif isinstance(ttype, Function):
return typeToCTypeDeclaration(ttype.resultType)+ " "+ttype.name+"("+string.join([typeToCTypeDeclaration(arg) for arg in ttype.argFieldList], ", ")+")"
elif isinstance(ttype, Field):
return typeToCTypeDeclaration(ttype.type)+ " "+ttype.name
else:
raise Exception, "Unknown type "+str(ttype)
def writeTypeDefDefinition(cfile, typedef):
cfile.writeln("typedef "+typeToCTypeDeclaration(typedef.definitionType)+" "+typedef.name+";")
def writeEnumDefinition(cfile, enum):
cfile.write("enum "+enum.name+" ");
cfile.beginBlock();
first = True
for ed in enum.enumDefs:
if first:
first = False
else:
cfile.writeln(",")
cfile.write(ed.name+" = "+str(ed.id))
cfile.writeln()
cfile.endBlock(";");
def writeStructDefinition(cfile, struct):
cfile.write("struct "+struct.name+" ");
cfile.beginBlock()
for field in struct.fieldList:
cfile.writeln(typeToCTypeDeclaration(field)+";")
cfile.endBlock(";")
CPP_DEFINITION_WRITER_MAP = {
TypeDef : writeTypeDefDefinition,
Enum : writeEnumDefinition,
Struct : writeStructDefinition,
Service : None
}
def writeDefinitions(cfile, definitions):
for definition in definitions:
writer = CPP_DEFINITION_WRITER_MAP[type(definition)]
if writer:
writer(cfile, definition)
cfile.writeln()
CPP_THRIFT_NS = "facebook::thrift"
CPP_INTERFACE_FUNCTION_DECLARATION = Template(""" virtual ${functionDeclaration} = 0;
""")
CPP_INTERFACE_DECLARATION = Template("""
class ${service}If {
public:
~${service}If() {}
${functionDeclarations}};
""")
def writeServiceInterfaceDeclaration(cfile, service, debugp=None):
functionDeclarations = string.join([CPP_INTERFACE_FUNCTION_DECLARATION.substitute(service=service.name, functionDeclaration=typeToCTypeDeclaration(function)) for function in service.functionList], "")
cfile.write(CPP_INTERFACE_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations))
CPP_SP = Template("boost::shared_ptr<${klass}> ")
CPP_PROCESSOR = CPP_THRIFT_NS+"::TProcessor"
CPP_PROCESSORP = CPP_SP.substitute(klass=CPP_PROCESSOR)
CPP_PROTOCOL_NS = CPP_THRIFT_NS+"::protocol"
CPP_PROTOCOL = CPP_PROTOCOL_NS+"::TProtocol"
CPP_PROTOCOLP = CPP_SP.substitute(klass="const "+CPP_PROTOCOL)
CPP_TRANSPORT_NS = CPP_THRIFT_NS+"::transport"
CPP_TRANSPORT = CPP_TRANSPORT_NS+"::TTransport"
CPP_TRANSPORTP = CPP_SP.substitute(klass=CPP_TRANSPORT)
CPP_SERVER_FUNCTION_DECLARATION = Template(""" void process_${function}("""+CPP_TRANSPORTP+""" _itrans, """+CPP_TRANSPORTP+""" _otrans);
""")
CPP_PROTOCOL_TSTOP = CPP_PROTOCOL_NS+"::T_STOP"
CPP_PROTOCOL_TTYPE = CPP_PROTOCOL_NS+"::TType"
CPP_TTYPE_MAP = {
STOP_TYPE : CPP_PROTOCOL_NS+"::T_STOP",
VOID_TYPE : CPP_PROTOCOL_NS+"::T_VOID",
BOOL_TYPE : CPP_PROTOCOL_NS+"::T_BOOL",
UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
UTF7_TYPE : CPP_PROTOCOL_NS+"::T_UTF7",
UTF8_TYPE : CPP_PROTOCOL_NS+"::T_UTF8",
UTF16_TYPE : CPP_PROTOCOL_NS+"::T_UTF16",
U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
I08_TYPE : CPP_PROTOCOL_NS+"::T_I08",
I16_TYPE : CPP_PROTOCOL_NS+"::T_I16",
I32_TYPE : CPP_PROTOCOL_NS+"::T_I32",
I64_TYPE : CPP_PROTOCOL_NS+"::T_I64",
U08_TYPE : CPP_PROTOCOL_NS+"::T_U08",
U16_TYPE : CPP_PROTOCOL_NS+"::T_U16",
U32_TYPE : CPP_PROTOCOL_NS+"::T_U32",
U64_TYPE : CPP_PROTOCOL_NS+"::T_U64",
FLOAT_TYPE : CPP_PROTOCOL_NS+"::T_FLOAT",
Struct : CPP_PROTOCOL_NS+"::T_STRUCT",
List : CPP_PROTOCOL_NS+"::T_LIST",
Map : CPP_PROTOCOL_NS+"::T_MAP",
Set : CPP_PROTOCOL_NS+"::T_SET"
}
def toWireType(ttype):
if isinstance(ttype, PrimitiveType):
return CPP_TTYPE_MAP[ttype]
elif isinstance(ttype, Struct) or isinstance(ttype, CollectionType):
return CPP_TTYPE_MAP[type(ttype)]
else:
raise Exception, "No wire type for thrift type: "+str(ttype)
CPP_SERVER_DECLARATION = Template("""
class ${service}ServerIf : public ${service}If, public """+CPP_PROCESSOR+""" {
public:
${service}ServerIf("""+CPP_PROTOCOLP+""" protocol): _iprot(protocol), _oprot(protocol) {}
${service}ServerIf("""+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _iprot(iprot), _oprot(oprot) {}
virtual ~${service}ServerIf() {}
bool process("""+CPP_TRANSPORTP+""" _itrans,"""+CPP_TRANSPORTP+""" _otrans);
protected:
"""+CPP_PROTOCOLP+""" _iprot;
"""+CPP_PROTOCOLP+""" _oprot;
private:
${functionDeclarations}};
""")
def writeServerDeclaration(cfile, service, debugp=None):
functionDeclarations = string.join([CPP_SERVER_FUNCTION_DECLARATION.substitute(function=function.name) for function in service.functionList], "")
cfile.write(CPP_SERVER_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations))
CPP_CLIENT_FUNCTION_DECLARATION = Template(""" ${functionDeclaration};
""")
CPP_CLIENT_DECLARATION = Template("""
class ${service}Client : public ${service}If {
public:
${service}Client("""+CPP_TRANSPORTP+""" transport, """+CPP_PROTOCOLP+""" protocol): _itrans(transport), _otrans(transport), _iprot(protocol), _oprot(protocol) {}
${service}Client("""+CPP_TRANSPORTP+""" itrans, """+CPP_TRANSPORTP+""" otrans, """+CPP_PROTOCOLP+""" iprot, """+CPP_PROTOCOLP+""" oprot) : _itrans(itrans), _otrans(otrans), _iprot(iprot), _oprot(oprot) {}
${functionDeclarations}
private:
"""+CPP_TRANSPORTP+""" _itrans;
"""+CPP_TRANSPORTP+""" _otrans;
"""+CPP_PROTOCOLP+""" _iprot;
"""+CPP_PROTOCOLP+""" _oprot;
};""")
def writeClientDeclaration(cfile, service, debugp=None):
functionDeclarations = string.join([CPP_CLIENT_FUNCTION_DECLARATION.substitute(functionDeclaration=typeToCTypeDeclaration(function)) for function in service.functionList], "")
cfile.writeln(CPP_CLIENT_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations))
def writeServiceDeclaration(cfile, service, debugp=None):
writeServiceInterfaceDeclaration(cfile, service, debugp)
writeServerDeclaration(cfile, service, debugp)
writeClientDeclaration(cfile, service, debugp)
def toGenDir(filename, suffix="cpp-gen", debugp=None):
result = os.path.join(os.path.split(filename)[0], suffix)
if not os.path.exists(result):
os.mkdir(result)
return result
def toBasename(filename, debugp=None):
""" Take the filename minus the path and\".thrift\" extension if present """
basename = os.path.split(filename)[1]
tokens = os.path.splitext(basename)
if tokens[1].lower() == ".thrift":
basename = tokens[0]
if debugp:
debugp("toBasename("+str(filename)+") => "+str(basename))
return basename
def toDefinitionHeaderName(filename, genDir=None, debugp=None):
if not genDir:
genDir = toGenDir(filename)
basename = toBasename(filename)
result = os.path.join(genDir, basename+"_types.h")
if debugp:
debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
return result
def writeDefinitionHeader(program, filename, genDir=None, debugp=None):
definitionHeader = toDefinitionHeaderName(filename, genDir)
if debugp:
debugp("definitionHeader: "+str(definitionHeader))
cfile = CFile(definitionHeader, "w")
basename = toBasename(filename)
cfile.writeln(CPP_TYPES_HEADER.substitute(source=basename, date=time.ctime()))
writeDefinitions(cfile, program.definitions)
cfile.writeln(CPP_TYPES_FOOTER.substitute(source=basename))
cfile.close()
def toServicesHeaderName(filename, genDir=None, debugp=None):
if not genDir:
genDir = toGenDir(filename)
basename = toBasename(filename)
result = os.path.join(genDir, basename+".h")
if debugp:
debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
return result
def writeServicesHeader(program, filename, genDir=None, debugp=None):
servicesHeader = toServicesHeaderName(filename, genDir)
if debugp:
debugp("servicesHeader: "+str(servicesHeader))
cfile = CFile(servicesHeader, "w")
basename = toBasename(filename)
cfile.writeln(CPP_SERVICES_HEADER.substitute(source=basename, date=time.ctime()))
services = []
# Build orderered list of service definitions by scanning definitions list for services
for definition in program.definitions:
if isinstance(definition, Service) and definition.name in program.serviceMap:
services.append(definition)
for service in services:
writeServiceDeclaration(cfile, service)
cfile.writeln(CPP_SERVICES_FOOTER.substitute(source=basename))
cfile.close()
CPP_STRUCT_READ = Template("""
uint32_t read${name}Struct("""+CPP_PROTOCOLP+""" _iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
std::string name;
uint32_t id;
uint32_t type;
uint32_t xfer = 0;
while(true) {
xfer+= _iprot->readFieldBegin(_itrans, name, type, id);
if(type == """+CPP_PROTOCOL_TSTOP+""") {
break;
}
switch(id) {
${readFieldListSwitch}
}
}
xfer+= _iprot->readStructEnd(_itrans);
return xfer;
}
""")
CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = {
"bool" : "Bool",
"string": "String",
"utf7": "String",
"utf8": "String",
"utf16": "String",
"i08": "Byte",
"i16": "I16",
"i32": "I32",
"i64": "I64",
"u08": "Byte",
"u16": "U16",
"u32": "U32",
"u64": "U64",
"float": "Double"
}
CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP = {
Map : "map",
List : "list",
Set : "set"
}
def typeToIOMethodSuffix(ttype):
if isinstance(ttype, PrimitiveType):
return CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP[ttype.name]
elif isinstance(ttype, CollectionType):
result = CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP[type(ttype)]+"_"
if isinstance(ttype, Map):
result+= "k_"+typeToIOMethodSuffix(ttype.keyType)+"_"
result += "v_"+typeToIOMethodSuffix(ttype.valueType)
return result
elif isinstance(ttype, Struct):
return "struct_"+ttype.name
elif isinstance(ttype, TypeDef):
return ttype.name
elif isinstance(ttype, Enum):
return ttype.name
else:
raise Exception, "Unknown type "+str(ttype)
def toReaderCall(value, ttype):
suffix = typeToIOMethodSuffix(ttype)
if isinstance(ttype, PrimitiveType):
return "xfer += iprot->read"+suffix+"(itrans, "+value+")"
elif isinstance(ttype, CollectionType):
return "xfer+= read_"+suffix+"(iprot, itrans, "+value+")"
elif isinstance(ttype, Struct):
return "xfer+= read_"+suffix+"(iprot, itrans, "+value+")"
elif isinstance(ttype, TypeDef):
return toReaderCall("reinterpret_cast<"+typeToCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType)
elif isinstance(ttype, Enum):
return toReaderCall("reinterpret_cast<"+typeToCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE)
else:
raise Exception, "Unknown type "+str(ttype)
def toWriterCall(value, ttype):
suffix = typeToIOMethodSuffix(ttype)
if isinstance(ttype, PrimitiveType):
return "xfer+= oprot->write"+suffix+"(otrans, "+value+")"
elif isinstance(ttype, CollectionType):
return "xfer+= write_"+suffix+"(oprot, otrans, "+value+")"
elif isinstance(ttype, Struct):
return "xfer+= write_"+suffix+"(oprot, otrans, "+value+")"
elif isinstance(ttype, TypeDef):
return toWriterCall("reinterpret_cast<const "+typeToCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType)
elif isinstance(ttype, Enum):
return toWriterCall("reinterpret_cast<const "+typeToCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE)
else:
raise Exception, "Unknown type "+str(ttype)
CPP_READ_MAP_DEFINITION = Template("""
uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
uint32_t count;
${keyType} key;
${valueType} elem;
uint32_t xfer = 0;
xfer += iprot->readU32(itrans, count);
for(int ix = 0; ix < count; ix++) {
${keyReaderCall};
${valueReaderCall};
value.insert(std::make_pair(key, elem));
}
return xfer;
}
""")
CPP_WRITE_MAP_DEFINITION = Template("""
uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
uint32_t xfer = 0;
xfer += oprot->writeU32(otrans, value.size());
for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
${keyWriterCall};
${valueWriterCall};
}
return xfer;
}
""")
CPP_READ_LIST_DEFINITION = Template("""
uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
uint32_t count;
${valueType} elem;
uint32_t xfer = 0;
xfer+= iprot->readU32(itrans, count);
for(int ix = 0; ix < count; ix++) {
${valueReaderCall};
value.${insert}(elem);
}
return xfer;
}
""")
CPP_WRITE_LIST_DEFINITION = Template("""
uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
uint32_t xfer = 0;
xfer+= oprot->writeU32(otrans, value.size());
for(${declaration}::const_iterator ix = value.begin(); ix != value.end(); ++ix) {
${valueWriterCall};
}
return xfer;
}
""")
def toCollectionReaderDefinition(ttype):
suffix = typeToIOMethodSuffix(ttype)
if isinstance(ttype, Map):
keyReaderCall = toReaderCall("key", ttype.keyType)
valueReaderCall= toReaderCall("elem", ttype.valueType)
if isinstance(ttype, Map):
return CPP_READ_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
keyType=typeToCTypeDeclaration(ttype.keyType),
keyReaderCall=keyReaderCall,
valueType=typeToCTypeDeclaration(ttype.valueType),
valueReaderCall=valueReaderCall)
else:
if isinstance(ttype, List):
insert="push_back"
else:
insert="insert"
return CPP_READ_LIST_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
valueReaderCall=valueReaderCall,
valueType=typeToCTypeDeclaration(ttype.valueType),
insert=insert)
def toCollectionWriterDefinition(ttype):
suffix = typeToIOMethodSuffix(ttype)
if isinstance(ttype, Map):
keyWriterCall = toWriterCall("ix->first", ttype.keyType)
valueWriterCall = toWriterCall("ix->second", ttype.valueType)
else:
valueWriterCall= toWriterCall("*ix", ttype.valueType)
if isinstance(ttype, Map):
return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
keyType=typeToCTypeDeclaration(ttype.keyType),
keyWriterCall=keyWriterCall,
valueType=typeToCTypeDeclaration(ttype.valueType),
valueWriterCall=valueWriterCall)
else:
return CPP_WRITE_LIST_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype),
valueWriterCall=valueWriterCall,
valueType=typeToCTypeDeclaration(ttype.valueType))
CPP_READ_STRUCT_DEFINITION = Template("""
uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itrans, ${declaration}& value) {
std::string name;
"""+CPP_PROTOCOL_TTYPE+""" type;
uint16_t id;
uint32_t xfer = 0;
while(true) {
xfer+= iprot->readFieldBegin(itrans, name, type, id);
if(type == """+CPP_PROTOCOL_TSTOP+""") {break;}
switch(id) {
${fieldSwitch}
default: xfer += iprot->skip(itrans, type); break;}
xfer+= iprot->readFieldEnd(itrans);
}
return xfer;
}
""")
CPP_WRITE_FIELD_DEFINITION = Template("""
oprot->writeFieldBegin(otrans, \"${name}\", ${type}, ${id});
${fieldWriterCall};
oprot->writeFieldEnd(otrans);
""")
CPP_WRITE_STRUCT_DEFINITION = Template("""
uint32_t write_${suffix}("""+CPP_PROTOCOLP+""" oprot, """+CPP_TRANSPORTP+""" otrans, const ${declaration}& value) {
uint32_t xfer = 0;
xfer+= oprot->writeStructBegin(otrans, \"${name}\");
${fieldWriterCalls}
xfer+= oprot->writeFieldStop(otrans);
xfer += oprot->writeStructEnd(otrans);
return xfer;
}
""")
def toStructReaderDefinition(ttype):
suffix = typeToIOMethodSuffix(ttype)
# Sort field list in order of increasing ids
fieldList = []
fieldList+= ttype.fieldList
fieldList.sort(lambda a,b: a.id - b.id)
fieldSwitch=""
for field in fieldList:
fieldSwitch+= " case "+str(field.id)+": "
fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; break;\n"
return CPP_READ_STRUCT_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldSwitch=fieldSwitch)
def toStructWriterDefinition(ttype):
suffix = typeToIOMethodSuffix(ttype)
writeCalls = ""
for field in ttype.fieldList:
writeCalls+= CPP_WRITE_FIELD_DEFINITION.substitute(name=field.name, type=toWireType(field.type), id=field.id,
fieldWriterCall=toWriterCall("value."+field.name, field.type))
return CPP_WRITE_STRUCT_DEFINITION.substitute(name=ttype.name, suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldWriterCalls=writeCalls)
def toReaderDefinition(ttype):
if isinstance(ttype, CollectionType):
return toCollectionReaderDefinition(ttype)
elif isinstance(ttype, Struct):
return toStructReaderDefinition(ttype)
elif isinstance(ttype, TypeDef):
return ""
elif isinstance(ttype, Enum):
return ""
else:
raise Exception, "Unsupported type: "+str(ttype)
def toWriterDefinition(ttype):
if isinstance(ttype, CollectionType):
return toCollectionWriterDefinition(ttype)
elif isinstance(ttype, Struct):
return toStructWriterDefinition(ttype)
elif isinstance(ttype, TypeDef):
return ""
elif isinstance(ttype, Enum):
return ""
else:
raise Exception, "Unsupported type: "+str(ttype)
def toOrderedIOList(ttype, result=None):
if not result:
result = []
if ttype in result:
return result
elif isinstance(ttype, PrimitiveType):
return result
elif isinstance(ttype, CollectionType):
if isinstance(ttype, Map):
result = toOrderedIOList(ttype.keyType, result)
result = toOrderedIOList(ttype.valueType, result)
result.append(ttype)
elif isinstance(ttype, Struct):
for field in ttype.fieldList:
result = toOrderedIOList(field.type, result)
result.append(ttype)
elif isinstance(ttype, TypeDef):
result.append(ttype)
return result
elif isinstance(ttype, Enum):
result.append(ttype)
return result
elif isinstance(ttype, Program):
for struct in ttype.structMap.values():
result = toOrderedIOList(struct, result)
for service in ttype.serviceMap.values():
result = toOrderedIOList(service, result)
elif isinstance(ttype, Service):
for function in ttype.functionList:
result = toOrderedIOList(function, result)
elif isinstance(ttype, Function):
result = toOrderedIOList(ttype.resultType, result)
for arg in ttype.argFieldList:
result = toOrderedIOList(arg.type, result)
else:
raise Exception, "Unsupported thrift type: "+str(ttype)
return result
def toIOMethodImplementations(program):
# get orderede list of all types that need marshallers:
iolist = toOrderedIOList(program)
result = ""
for ttype in iolist:
result+= toReaderDefinition(ttype)
result+= toWriterDefinition(ttype)
return result;
def toImplementationSourceName(filename, genDir=None, debugp=None):
if not genDir:
genDir = toGenDir(filename)
basename = toBasename(filename)
result = os.path.join(genDir, basename+".cc")
if debugp:
debugp("toDefinitionHeaderName("+str(filename)+", "+str(genDir)+") => "+str(basename))
return result
def writeImplementationSource(program, filename, genDir=None, debugp=None):
implementationSource = toImplementationSourceName(filename, genDir)
if debugp:
debugp("implementationSource: "+str(implementationSource))
cfile = CFile(implementationSource, "w")
basename = toBasename(filename)
cfile.writeln(CPP_IMPL_HEADER.substitute(source=basename, date=time.ctime()))
cfile.write(toIOMethodImplementations(program))
cfile.writeln(CPP_IMPL_FOOTER.substitute(source=basename))
cfile.close()
class CPPGenerator(Generator):
def __call__(self, program, filename, genDir=None, debugp=None):
writeDefinitionHeader(program, filename, genDir, debugp)
writeServicesHeader(program, filename, genDir, debugp)
writeImplementationSource(program, filename, genDir, debugp)