From 5b126d6c85e1c23656fb9be43aba5df9a161635d Mon Sep 17 00:00:00 2001 From: Marc Slemko Date: Fri, 11 Aug 2006 23:03:42 +0000 Subject: [PATCH] Groundwork for exception support: Auto generate result structs that combine return type and any thrown exceptions Add __isset struct to all user defined and auto defined struct to mark fields that are explicilty read Modified client and server generation code to marshal result structs Added base facebook::thrift::Exception class git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664750 13f79535-47bb-0310-9956-ffa450edef68 --- compiler/src/cpp_generator.py | 325 ++++++++++++++++++++++--------- compiler/src/parser.py | 57 +++--- lib/cpp/src/Thrift.h | 15 ++ lib/cpp/src/protocol/TProtocol.h | 37 ++-- test/ThriftTest.thrift | 2 + 5 files changed, 300 insertions(+), 136 deletions(-) diff --git a/compiler/src/cpp_generator.py b/compiler/src/cpp_generator.py index f67ca00c..2c8efc51 100644 --- a/compiler/src/cpp_generator.py +++ b/compiler/src/cpp_generator.py @@ -117,9 +117,9 @@ CPP_PRIMITIVE_MAP = { } CPP_CONTAINER_MAP = { - Map : "std::map", - List: "std::list", - Set : "std::set", + MapType : "std::map", + ListType: "std::list", + SetType : "std::set", } def typeToCTypeDeclaration(ttype): @@ -131,10 +131,10 @@ def typeToCTypeDeclaration(ttype): result = CPP_CONTAINER_MAP[type(ttype)]+"<" - if isinstance(ttype, Map): + if isinstance(ttype, MapType): result+= typeToCTypeDeclaration(ttype.keyType)+", "+ typeToCTypeDeclaration(ttype.valueType) - elif isinstance(ttype, Set) or isinstance(ttype, List): + elif isinstance(ttype, SetType) or isinstance(ttype, ListType): result+= typeToCTypeDeclaration(ttype.valueType) else: @@ -144,17 +144,17 @@ def typeToCTypeDeclaration(ttype): return result - elif isinstance(ttype, Struct): + elif isinstance(ttype, StructType): return "struct "+ttype.name - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return ttype.name; - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return ttype.name; elif isinstance(ttype, Function): - return typeToCTypeDeclaration(ttype.resultType)+ " "+ttype.name+"("+string.join([typeToCTypeDeclaration(arg) for arg in ttype.argsStruct.fieldList], ", ")+")" + return typeToCTypeDeclaration(ttype.returnType())+ " "+ttype.name+"("+string.join([typeToCTypeDeclaration(arg) for arg in ttype.args()], ", ")+")" elif isinstance(ttype, Field): return typeToCTypeDeclaration(ttype.type)+ " "+ttype.name @@ -189,16 +189,23 @@ def toStructDefinition(struct): result = "struct "+struct.name+" {\n" for field in struct.fieldList: - result += " "+typeToCTypeDeclaration(field)+";\n" + if toCanonicalType(field.type) != VOID_TYPE: + result += " "+typeToCTypeDeclaration(field)+";\n" + + result+= " struct {\n" + + for field in struct.fieldList: + result+= " bool "+field.name+";\n" + result+= " } __isset;\n" result+= "};\n" return result CPP_DEFINITION_MAP = { - TypeDef : toTypeDefDefinition, - Enum : toEnumDefinition, - Struct : toStructDefinition, + TypedefType : toTypeDefDefinition, + EnumType : toEnumDefinition, + StructType : toStructDefinition, Service : None } @@ -233,6 +240,8 @@ def toServiceInterfaceDeclaration(service, debugp=None): return CPP_INTERFACE_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations) +CPP_EXCEPTION = CPP_THRIFT_NS+"::Exception" + CPP_SP = Template("boost::shared_ptr<${klass}> ") CPP_PROCESSOR = CPP_THRIFT_NS+"::TProcessor" @@ -255,11 +264,19 @@ void ${service}ServerIf::process_${function}("""+CPP_TRANSPORTP+""" itrans, """+ uint32_t xfer = 0; -${argsStructDeclaration} -${argsStructReader} -${resultDeclaration} -${functionCall} -${resultWriter} + ${argsStructDeclaration}; + + ${argsStructReader}; + + ${returnValueDeclaration}; + + ${functionCall}; + + ${resultStructDeclaration}; + + ${returnToResult}; + + ${resultStructWriter}; otrans->flush(); } @@ -267,6 +284,9 @@ ${resultWriter} CPP_PROTOCOL_TSTOP = CPP_PROTOCOL_NS+"::T_STOP" CPP_PROTOCOL_TTYPE = CPP_PROTOCOL_NS+"::TType" +CPP_PROTOCOL_MESSAGE_TYPE = CPP_PROTOCOL_NS+"::TMessageType" +CPP_PROTOCOL_CALL = CPP_PROTOCOL_NS+"::T_CALL" +CPP_PROTOCOL_REPLY = CPP_PROTOCOL_NS+"::T_REPLY" CPP_TTYPE_MAP = { STOP_TYPE : CPP_PROTOCOL_NS+"::T_STOP", @@ -286,10 +306,10 @@ CPP_TTYPE_MAP = { 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" + StructType : CPP_PROTOCOL_NS+"::T_STRUCT", + ListType : CPP_PROTOCOL_NS+"::T_LIST", + MapType : CPP_PROTOCOL_NS+"::T_MAP", + SetType : CPP_PROTOCOL_NS+"::T_SET" } def toWireType(ttype): @@ -297,13 +317,13 @@ def toWireType(ttype): if isinstance(ttype, PrimitiveType): return CPP_TTYPE_MAP[ttype] - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return CPP_TTYPE_MAP[I32_TYPE] - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return toWireType(toCanonicalType(ttype)) - elif isinstance(ttype, Struct) or isinstance(ttype, CollectionType): + elif isinstance(ttype, StructType) or isinstance(ttype, CollectionType): return CPP_TTYPE_MAP[type(ttype)] else: @@ -332,6 +352,46 @@ def toServerDeclaration(service, debugp=None): CPP_CLIENT_FUNCTION_DECLARATION = Template(""" ${functionDeclaration}; """) + +CPP_CLIENT_FUNCTION_DEFINITION = Template(""" +${returnDeclaration} ${service}Client::${function}(${argsDeclaration}) { + + uint32_t xfer = 0; + """+CPP_PROTOCOL_MESSAGE_TYPE+""" messageType; + uint32_t cseqid = 0; + uint32_t rseqid = 0; + + _oprot->writeMessageBegin(_otrans, """+CPP_PROTOCOL_CALL+""", cseqid); + + ${argsStructDeclaration}; + +${argsToStruct}; + + ${argsStructWriter}; + + _otrans->flush(); + + _iprot->readMessageBegin(_itrans, messageType, rseqid); + + if(messageType != """+CPP_PROTOCOL_REPLY+""" || + rseqid != cseqid) { + throw """+CPP_EXCEPTION+"""(\"unexpected message type or id\"); + } + + ${resultStructDeclaration}; + + ${resultStructReader}; + + _iprot->readMessageEnd(_itrans); + + if(__result.__isset.success) { + ${success}; + } else { + throw """+CPP_EXCEPTION+"""(\"${function} failed\"); + } +} +""") + CPP_CLIENT_DECLARATION = Template(""" class ${service}Client : public ${service}If { @@ -349,36 +409,48 @@ ${functionDeclarations} """+CPP_PROTOCOLP+""" _oprot; };""") -def toServerServiceDefinition(service, debugp=None): - +def toServerFunctionDefinition(servicePrefix, function, debugp=None): result = "" - for function in service.functionList: + argsStructDeclaration = typeToCTypeDeclaration(function.argsStruct)+" __args" - if len(function.argsStruct.fieldList) > 0: - argsStructDeclaration = " "+typeToCTypeDeclaration(function.argsStruct)+" __args;\n" - argsStructReader = " "+toReaderCall("__args", function.argsStruct, "_iprot")+";\n" - else: - argsStructDeclaration = "" - argsStructReader = "" + argsStructReader = toReaderCall("__args", function.argsStruct, "_iprot") + + resultStructDeclaration = typeToCTypeDeclaration(function.resultStruct)+" __result" - functionCall = " " - resultDeclaration = "" - resultWriter = "" + resultStructWriter = toWriterCall("__result", function.resultStruct, "_oprot") - if toCanonicalType(function.resultType) != VOID_TYPE: - resultDeclaration = " "+typeToCTypeDeclaration(function.resultType)+" __result;\n" - functionCall+= "__result = " + if function.returnType() != VOID_TYPE: + returnValueDeclaration = typeToCTypeDeclaration(toCanonicalType(function.returnType()))+" __returnValue" + functionCall = "__returnValue = " + returnToResult = "__result.success = __returnValue" + else: + returnValueDeclaration = "" + functionCall = "" + returnToResult = "" - functionCall+= function.name+"("+string.join(["__args."+arg.name for arg in function.argsStruct.fieldList], ", ")+");\n" + functionCall+= function.name+"("+string.join(["__args."+arg.name for arg in function.args()], ", ")+")" - if toCanonicalType(function.resultType) != VOID_TYPE: - resultWriter = " "+toWriterCall("__result", function.resultType, "_oprot")+";" + result+= CPP_SERVER_FUNCTION_DEFINITION.substitute(service=servicePrefix, function=function.name, + argsStructDeclaration=argsStructDeclaration, + argsStructReader=argsStructReader, + functionCall=functionCall, + returnToResult=returnToResult, + resultStructDeclaration=resultStructDeclaration, + resultStructWriter=resultStructWriter, + returnValueDeclaration=returnValueDeclaration) - result+= CPP_SERVER_FUNCTION_DEFINITION.substitute(service=service.name, function=function.name, - argsStructDeclaration=argsStructDeclaration, argsStructReader=argsStructReader, - functionCall=functionCall, - resultDeclaration=resultDeclaration, resultWriter=resultWriter) + + + return result + +def toServerServiceDefinition(service, debugp=None): + + result = "" + + for function in service.functionList: + + result+= toServerFunctionDefinition(service.name, function, debugp) return result @@ -392,6 +464,53 @@ def toClientDeclaration(service, debugp=None): return CPP_CLIENT_DECLARATION.substitute(service=service.name, functionDeclarations=functionDeclarations)+"\n" +def toClientFunctionDefinition(servicePrefix, function, debugp=None): + + returnDeclaration = typeToCTypeDeclaration(function.returnType()) + + argsDeclaration = string.join([typeToCTypeDeclaration(function.args()[ix].type)+" __arg"+str(ix) for ix in range(len(function.args()))], ", ") + + argsStructDeclaration = typeToCTypeDeclaration(function.argsStruct)+" __args" + + argsStructWriter = toWriterCall("__args", function.argsStruct, "_oprot", "_otrans") + + argsToStruct= string.join([" __args."+function.args()[ix].name+" = __arg"+str(ix) for ix in range(len(function.args()))], ";\n") + + resultStructDeclaration = typeToCTypeDeclaration(function.resultStruct)+" __result" + + resultStructReader = toReaderCall("__result", function.resultStruct, "_iprot", "_itrans") + + if(toCanonicalType(function.returnType()) != VOID_TYPE): + + success = "return __result.success;" + else: + success = "" + + return CPP_CLIENT_FUNCTION_DEFINITION.substitute(service=servicePrefix, + function=function.name, + returnDeclaration=returnDeclaration, + argsDeclaration=argsDeclaration, + argsStructDeclaration=argsStructDeclaration, + argsStructWriter=argsStructWriter, + argsToStruct=argsToStruct, + resultStructDeclaration=resultStructDeclaration, + resultStructReader=resultStructReader, + success=success) + +def toClientServiceDefinition(service, debugp=None): + + result = "" + + for function in service.functionList: + + result+= toClientFunctionDefinition(service.name, function) + + return result + +def toClientDefinition(program, debugp=None): + + return string.join([toClientServiceDefinition(service) for service in program.serviceMap.values()], "\n") + def toServiceDeclaration(service, debugp=None): return toServiceInterfaceDeclaration(service, debugp) + toServerDeclaration(service, debugp) + toClientDeclaration(service, debugp) @@ -522,6 +641,7 @@ ${readFieldListSwitch} """) CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = { + "void" :"Void", "bool" : "Bool", "string": "String", "utf7": "String", @@ -539,9 +659,9 @@ CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = { } CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP = { - Map : "map", - List : "list", - Set : "set" + MapType : "map", + ListType : "list", + SetType : "set" } def typeToIOMethodSuffix(ttype): @@ -553,64 +673,70 @@ def typeToIOMethodSuffix(ttype): result = CPP_COLLECTION_TYPE_IO_METHOD_SUFFIX_MAP[type(ttype)]+"_" - if isinstance(ttype, Map): + if isinstance(ttype, MapType): result+= "k_"+typeToIOMethodSuffix(ttype.keyType)+"_" result += "v_"+typeToIOMethodSuffix(ttype.valueType) return result - elif isinstance(ttype, Struct): + elif isinstance(ttype, StructType): return "struct_"+ttype.name - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return ttype.name - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return ttype.name else: raise Exception, "Unknown type "+str(ttype) -def toReaderCall(value, ttype, reader="iprot"): +def toReaderCall(value, ttype, reader="iprot", transport="itrans"): suffix = typeToIOMethodSuffix(ttype) if isinstance(ttype, PrimitiveType): - return "xfer += "+reader+"->read"+suffix+"(itrans, "+value+")" + if ttype != VOID_TYPE: + return "xfer += "+reader+"->read"+suffix+"("+transport+", "+value+")" + else: + return "" elif isinstance(ttype, CollectionType): - return "xfer+= read_"+suffix+"("+reader+", itrans, "+value+")" + return "xfer+= read_"+suffix+"("+reader+", "+transport+", "+value+")" - elif isinstance(ttype, Struct): - return "xfer+= read_"+suffix+"("+reader+", itrans, "+value+")" + elif isinstance(ttype, StructType): + return "xfer+= read_"+suffix+"("+reader+", "+transport+", "+value+")" - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return toReaderCall("reinterpret_cast<"+typeToCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, reader) - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return toReaderCall("reinterpret_cast<"+typeToCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, reader) else: raise Exception, "Unknown type "+str(ttype) -def toWriterCall(value, ttype, writer="oprot"): +def toWriterCall(value, ttype, writer="oprot", transport="otrans"): suffix = typeToIOMethodSuffix(ttype) if isinstance(ttype, PrimitiveType): - return "xfer+= "+writer+"->write"+suffix+"(otrans, "+value+")" + if ttype != VOID_TYPE: + return "xfer+= "+writer+"->write"+suffix+"("+transport+", "+value+")" + else: + return "" elif isinstance(ttype, CollectionType): - return "xfer+= write_"+suffix+"("+writer+", otrans, "+value+")" + return "xfer+= write_"+suffix+"("+writer+", "+transport+", "+value+")" - elif isinstance(ttype, Struct): - return "xfer+= write_"+suffix+"("+writer+", otrans, "+value+")" + elif isinstance(ttype, StructType): + return "xfer+= write_"+suffix+"("+writer+", "+transport+", "+value+")" - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return toWriterCall("reinterpret_cast("+value+")", ttype.definitionType, writer) - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return toWriterCall("reinterpret_cast("+value+")", I32_TYPE, writer) else: @@ -686,12 +812,12 @@ def toCollectionReaderDefinition(ttype): suffix = typeToIOMethodSuffix(ttype) - if isinstance(ttype, Map): + if isinstance(ttype, MapType): keyReaderCall = toReaderCall("key", ttype.keyType) valueReaderCall= toReaderCall("elem", ttype.valueType) - if isinstance(ttype, Map): + if isinstance(ttype, MapType): return CPP_READ_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype), keyType=typeToCTypeDeclaration(ttype.keyType), keyReaderCall=keyReaderCall, @@ -699,7 +825,7 @@ def toCollectionReaderDefinition(ttype): valueReaderCall=valueReaderCall) else: - if isinstance(ttype, List): + if isinstance(ttype, ListType): insert="push_back" else: insert="insert" @@ -714,14 +840,14 @@ def toCollectionWriterDefinition(ttype): suffix = typeToIOMethodSuffix(ttype) - if isinstance(ttype, Map): + if isinstance(ttype, MapType): keyWriterCall = toWriterCall("ix->first", ttype.keyType) valueWriterCall = toWriterCall("ix->second", ttype.valueType) else: valueWriterCall= toWriterCall("*ix", ttype.valueType) - if isinstance(ttype, Map): + if isinstance(ttype, MapType): return CPP_WRITE_MAP_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype), keyType=typeToCTypeDeclaration(ttype.keyType), keyWriterCall=keyWriterCall, @@ -742,6 +868,8 @@ uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itra int16_t id; uint32_t xfer = 0; + xfer+= iprot->readStructBegin(itrans, name); + while(true) { xfer+= iprot->readFieldBegin(itrans, name, type, id); @@ -750,10 +878,14 @@ uint32_t read_${suffix}("""+CPP_PROTOCOLP+""" iprot, """+CPP_TRANSPORTP+""" itra switch(id) { ${fieldSwitch} - default: xfer += iprot->skip(itrans, type); break;} + default: xfer += iprot->skip(itrans, type); break; + } xfer+= iprot->readFieldEnd(itrans); } + + xfer+= iprot->readStructEnd(itrans); + return xfer; } """) @@ -792,7 +924,7 @@ def toStructReaderDefinition(ttype): for field in fieldList: fieldSwitch+= " case "+str(field.id)+": " - fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; break;\n" + fieldSwitch+= toReaderCall("value."+field.name, field.type)+"; value.__isset."+field.name+" = true; break;\n" return CPP_READ_STRUCT_DEFINITION.substitute(suffix=suffix, declaration=typeToCTypeDeclaration(ttype), fieldSwitch=fieldSwitch) @@ -813,13 +945,13 @@ def toReaderDefinition(ttype): if isinstance(ttype, CollectionType): return toCollectionReaderDefinition(ttype) - elif isinstance(ttype, Struct): + elif isinstance(ttype, StructType): return toStructReaderDefinition(ttype) - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return "" - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return "" else: @@ -829,13 +961,13 @@ def toWriterDefinition(ttype): if isinstance(ttype, CollectionType): return toCollectionWriterDefinition(ttype) - elif isinstance(ttype, Struct): + elif isinstance(ttype, StructType): return toStructWriterDefinition(ttype) - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): return "" - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): return "" else: @@ -853,23 +985,23 @@ def toOrderedIOList(ttype, result=None): elif isinstance(ttype, CollectionType): - if isinstance(ttype, Map): + if isinstance(ttype, MapType): result = toOrderedIOList(ttype.keyType, result) result = toOrderedIOList(ttype.valueType, result) result.append(ttype) - elif isinstance(ttype, Struct): + elif isinstance(ttype, StructType): for field in ttype.fieldList: result = toOrderedIOList(field.type, result) result.append(ttype) - elif isinstance(ttype, TypeDef): + elif isinstance(ttype, TypedefType): result.append(ttype) return result - elif isinstance(ttype, Enum): + elif isinstance(ttype, EnumType): result.append(ttype) return result @@ -886,13 +1018,13 @@ def toOrderedIOList(ttype, result=None): result = toOrderedIOList(function, result) elif isinstance(ttype, Function): - result = toOrderedIOList(ttype.resultType, result) + result = toOrderedIOList(ttype.returnType(), result) # skip the args struct itself and just order the arguments themselves - # we don't want the arg struct to be referred to until laters, since we need to + # we don't want the arg struct to be referred to until later, since we need to # inline those struct definitions with the implementation, not in the types header - for field in ttype.argsStruct.fieldList: + for field in ttype.args(): result = toOrderedIOList(field.type, result) else: @@ -912,19 +1044,20 @@ def toIOMethodImplementations(program): result+= toReaderDefinition(ttype) result+= toWriterDefinition(ttype) - # for all function argument lists we need to create both struct definitions - # and io methods. We keep the struct definitions local, since they aren't part of the service - # API + # For all function argument lists, we need to create both struct definitions + # and io methods. We keep the struct definitions local, since they aren't part of the service API + # # Note that we don't need to do a depth-first traverse of arg structs since they can only include fields # we've already seen for service in program.serviceMap.values(): for function in service.functionList: - if len(function.argsStruct.fieldList) == 0: - continue result+= toStructDefinition(function.argsStruct) - result+=toReaderDefinition(function.argsStruct) - result+=toWriterDefinition(function.argsStruct) + result+= toReaderDefinition(function.argsStruct) + result+= toWriterDefinition(function.argsStruct) + result+= toStructDefinition(function.resultStruct) + result+= toReaderDefinition(function.resultStruct) + result+= toWriterDefinition(function.resultStruct) return result; @@ -959,6 +1092,8 @@ def writeImplementationSource(program, filename, genDir=None, debugp=None): cfile.write(toServerDefinition(program)) + cfile.write(toClientDefinition(program)) + cfile.writeln(CPP_IMPL_FOOTER.substitute(source=basename)) cfile.close() diff --git a/compiler/src/parser.py b/compiler/src/parser.py index d2fb0fd4..e5c875a4 100644 --- a/compiler/src/parser.py +++ b/compiler/src/parser.py @@ -84,14 +84,14 @@ class Identifier(Definition): def toCanonicalType(ttype): - if isinstance(ttype, TypeDef): + if isinstance(ttype, TypedefType): return toCanonicalType(ttype.definitionType) else: return ttype def isComparableType(ttype): ttype = toCanonicalType(ttype) - return isinstance(ttype, PrimitiveType) or isinstance(ttype, Enum) + return isinstance(ttype, PrimitiveType) or isinstance(ttype, EnumType) class Type(Definition): """ Abstract Type definition """ @@ -103,7 +103,7 @@ class Type(Definition): def __str__(self): return self.name -class TypeDef(Type): +class TypedefType(Type): def __init__(self, symbols, name, definitionType): Type.__init__(self, symbols, name) @@ -167,7 +167,7 @@ class CollectionType(Type): def validate(self): return True -class Map(CollectionType): +class MapType(CollectionType): def __init__(self, symbols, keyType, valueType): CollectionType.__init__(self, symbols, "map<"+keyType.name+","+valueType.name +">") @@ -178,7 +178,7 @@ class Map(CollectionType): if not isComparableType(self.keyType): raise ErrorException([SymanticsError(self, "key type \""+str(self.keyType)+"\" is not a comparable type.")]) -class Set(CollectionType): +class SetType(CollectionType): def __init__(self, symbols, valueType): CollectionType.__init__(self, symbols, "set<"+valueType.name+">") @@ -188,13 +188,13 @@ class Set(CollectionType): if not isComparableType(self.valueType): raise ErrorException([SymanticsError(self, "value type \""+str(self.valueType)+"\" is not a comparable type.")]) -class List(CollectionType): +class ListType(CollectionType): def __init__(self, symbols, valueType): CollectionType.__init__(self, symbols, "list<"+valueType.name+">") self.valueType = valueType -class Enum(Definition): +class EnumType(Definition): def __init__(self, symbols, name, enumDefs): Definition.__init__(self, symbols, name) @@ -319,7 +319,7 @@ def validateFieldList(fieldList): if not field.id: currentId = assignId(field, currentId, ids) -class Struct(Type): +class StructType(Type): def __init__(self, symbols, name, fieldList): Type.__init__(self, symbols, name) @@ -333,16 +333,22 @@ class Struct(Type): class Function(Definition): - def __init__(self, symbols, name, resultType, argsStruct): + def __init__(self, symbols, name, resultStruct, argsStruct, ): Definition.__init__(self, symbols, name) - self.resultType = resultType + self.resultStruct = resultStruct self.argsStruct = argsStruct def validate(self): validateFieldList(self.argsStruct.fieldList) + + def args(self): + return self.argsStruct.fieldList + + def returnType(self): + return self.resultStruct.fieldList[0].type def __str__(self): - return self.name+"("+string.join(map(lambda a: str(a), self.argsStruct), ", ")+") => "+str(self.resultType) + return self.name+"("+string.join(map(lambda a: str(a), self.argsStruct), ", ")+") => "+str(self.resultStruct) class Service(Definition): @@ -472,7 +478,7 @@ class Program(object): for collection in self.collectionMap.values(): try: - if isinstance(collection, Map): + if isinstance(collection, MapType): collection.keyType = self.getType(collection, collection.keyType) collection.valueType = self.getType(collection, collection.valueType) @@ -494,10 +500,12 @@ class Program(object): for service in self.serviceMap.values(): for function in service.functionList: - try: - function.resultType = self.getType(service, function.resultType) - except ErrorException, e: - errors+= e.errors + + for field in function.resultStruct.fieldList: + try: + field.type = self.getType(function, field) + except ErrorException, e: + errors+= e.errors for field in function.argsStruct.fieldList: try: @@ -655,7 +663,7 @@ class Parser(object): def p_typedef(self, p): 'typedef : TYPEDEF definitiontype ID' self.pdebug("p_typedef", p) - p[0] = TypeDef(p, p[3], p[2]) + p[0] = TypedefType(p, p[3], p[2]) try: p[0].validate() @@ -665,7 +673,7 @@ class Parser(object): def p_enum(self, p): 'enum : ENUM ID LBRACE enumdeflist RBRACE' self.pdebug("p_enum", p) - p[0] = Enum(p, p[2], p[4]) + p[0] = EnumType(p, p[2], p[4]) try: p[0].validate() @@ -695,7 +703,7 @@ class Parser(object): def p_struct(self, p): 'struct : STRUCT ID LBRACE fieldlist RBRACE' self.pdebug("p_struct", p) - p[0] = Struct(p, p[2], p[4]) + p[0] = StructType(p, p[2], p[4]) try: p[0].validate() @@ -724,7 +732,10 @@ class Parser(object): def p_function(self, p): 'function : functiontype functionmodifiers ID LPAREN fieldlist RPAREN' self.pdebug("p_function", p) - p[0] = Function(p, p[3], p[1], Struct(p, p[3]+"_args", p[5])) + + resultStruct = StructType(p, p[3]+"_result", (Field(p, p[1], Identifier(None, "success", 1)),)) + + p[0] = Function(p, p[3], resultStruct, StructType(p, p[3]+"_args", p[5])) try: p[0].validate() except ErrorException, e: @@ -878,17 +889,17 @@ class Parser(object): def p_maptype(self, p): 'maptype : MAP LANGLE fieldtype COMMA fieldtype RANGLE' self.pdebug("p_maptype", p) - p[0] = Map(p, p[3], p[5]) + p[0] = MapType(p, p[3], p[5]) def p_settype(self, p): 'settype : SET LANGLE fieldtype RANGLE' self.pdebug("p_settype", p) - p[0] = Set(p, p[3]) + p[0] = SetType(p, p[3]) def p_listtype(self, p): 'listtype : LIST LANGLE fieldtype RANGLE' self.pdebug("p_listtype", p) - p[0] = List(p, p[3]) + p[0] = ListType(p, p[3]) def p_error(self, p): # p_error is called with an empty token if eof was encountered unexpectedly. diff --git a/lib/cpp/src/Thrift.h b/lib/cpp/src/Thrift.h index 9986e3bd..1f98d82c 100644 --- a/lib/cpp/src/Thrift.h +++ b/lib/cpp/src/Thrift.h @@ -7,5 +7,20 @@ #include #include #include +#include + +namespace facebook {namespace thrift { + +class Exception : public std::exception { +private: + const std::string _message; + +public: + Exception(const std::string message) : _message(message) {} + ~Exception() throw () {} + const char* what() {return _message.c_str();} +}; + +}} // facebook::thrift #endif diff --git a/lib/cpp/src/protocol/TProtocol.h b/lib/cpp/src/protocol/TProtocol.h index 8c89ba5a..329b7bf6 100644 --- a/lib/cpp/src/protocol/TProtocol.h +++ b/lib/cpp/src/protocol/TProtocol.h @@ -30,23 +30,24 @@ struct TBuf; */ enum TType { T_STOP = 0, - T_BOOL = 1, - T_BYTE = 2, - T_U08 = 2, - T_U16 = 3, - T_I16 = 4, - T_U32 = 5, - T_I32 = 6, - T_U64 = 7, - T_I64 = 8, - T_STRING = 9, - T_UTF7 = 9, - T_STRUCT = 10, - T_MAP = 11, - T_SET = 12, - T_LIST = 13, - T_UTF8 = 14, - T_UTF16 = 15 + T_VOID = 1, + T_BOOL = 2, + T_BYTE = 3, + T_U08 = 4, + T_U16 = 5, + T_I16 = 6, + T_U32 = 7, + T_I32 = 8, + T_U64 = 9, + T_I64 = 10, + T_STRING = 11, + T_UTF7 = 12, + T_STRUCT = 13, + T_MAP = 14, + T_SET = 15, + T_LIST = 16, + T_UTF8 = 17, + T_UTF16 = 18 }; /** @@ -148,7 +149,7 @@ class TProtocol { * Reading functions */ - virtual uint32_t readMessasgeBegin(shared_ptr in, + virtual uint32_t readMessageBegin(shared_ptr in, TMessageType& messageType, uint32_t& seqid) const = 0; diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift index 2e887258..64c045a3 100644 --- a/test/ThriftTest.thrift +++ b/test/ThriftTest.thrift @@ -31,6 +31,8 @@ struct Insanity list xtructList = 1 } +struct Empty {} + service ThriftTest { void testVoid() -- 2.17.1