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
diff --git a/compiler/src/cpp_generator.py b/compiler/src/cpp_generator.py
index f67ca00..2c8efc5 100644
--- a/compiler/src/cpp_generator.py
+++ b/compiler/src/cpp_generator.py
@@ -117,9 +117,9 @@
 }
 
 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 @@
 
         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 @@
 
         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 @@
     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 @@
 
     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 @@
 
     uint32_t xfer = 0;
 
-${argsStructDeclaration}
-${argsStructReader}    
-${resultDeclaration}
-${functionCall}
-${resultWriter}
+    ${argsStructDeclaration};
+
+    ${argsStructReader};
+
+    ${returnValueDeclaration};
+
+    ${functionCall};
+
+    ${resultStructDeclaration};
+
+    ${returnToResult};
+
+    ${resultStructWriter};
 
     otrans->flush();
 }
@@ -267,6 +284,9 @@
 
 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 @@
     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 @@
     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 @@
 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 @@
     """+CPP_PROTOCOLP+""" _oprot;
 };""")
 
+def toServerFunctionDefinition(servicePrefix, function, debugp=None):
+    result = ""
+
+    argsStructDeclaration = typeToCTypeDeclaration(function.argsStruct)+" __args"
+
+    argsStructReader = toReaderCall("__args", function.argsStruct, "_iprot")
+
+    resultStructDeclaration = typeToCTypeDeclaration(function.resultStruct)+" __result"
+
+    resultStructWriter = toWriterCall("__result", function.resultStruct, "_oprot")
+
+    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.args()], ", ")+")"
+
+    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)
+
+    
+
+    return result
+
 def toServerServiceDefinition(service, debugp=None):
 
     result = ""
 
     for function in service.functionList:
-
-	if len(function.argsStruct.fieldList) > 0:
-	    argsStructDeclaration = "    "+typeToCTypeDeclaration(function.argsStruct)+" __args;\n"
-	    argsStructReader = "    "+toReaderCall("__args", function.argsStruct, "_iprot")+";\n"
-	else:
-	    argsStructDeclaration = ""
-	    argsStructReader = ""
-
-	functionCall = "    "
-	resultDeclaration = ""
-	resultWriter = ""
-
-	if toCanonicalType(function.resultType) != VOID_TYPE:
-	    resultDeclaration = "    "+typeToCTypeDeclaration(function.resultType)+" __result;\n"
-	    functionCall+= "__result = "
-
-	functionCall+= function.name+"("+string.join(["__args."+arg.name for arg in function.argsStruct.fieldList], ", ")+");\n"
-
-	if toCanonicalType(function.resultType) != VOID_TYPE:
-	    resultWriter = "    "+toWriterCall("__result", function.resultType, "_oprot")+";"
-
-	result+= CPP_SERVER_FUNCTION_DEFINITION.substitute(service=service.name, function=function.name,
-							   argsStructDeclaration=argsStructDeclaration, argsStructReader=argsStructReader, 
-							   functionCall=functionCall,
-							   resultDeclaration=resultDeclaration, resultWriter=resultWriter)
+	
+	result+= toServerFunctionDefinition(service.name, function, debugp)
 
     return result
 
@@ -392,6 +464,53 @@
 
     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 @@
 """)
 
 CPP_PRIMITIVE_TYPE_IO_METHOD_SUFFIX_MAP = {
+    "void" :"Void",
     "bool" : "Bool",
     "string": "String",
     "utf7": "String",
@@ -539,9 +659,9 @@
 }
 
 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 @@
 
         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<const "+typeToCTypeDeclaration(ttype.definitionType)+"&>("+value+")", ttype.definitionType, writer)
 
-    elif isinstance(ttype, Enum):
+    elif isinstance(ttype, EnumType):
         return toWriterCall("reinterpret_cast<const "+typeToCTypeDeclaration(I32_TYPE)+"&>("+value+")", I32_TYPE, writer)
 
     else:
@@ -686,12 +812,12 @@
 
     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 @@
                                                   valueReaderCall=valueReaderCall)
 
     else:
-	if isinstance(ttype, List):
+	if isinstance(ttype, ListType):
 	    insert="push_back"
 	else:
 	    insert="insert"
@@ -714,14 +840,14 @@
 
     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 @@
     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 @@
 
         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 @@
 
     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 @@
     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 @@
     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 @@
 
     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 @@
 	    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 @@
 	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 @@
 
     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 d2fb0fd..e5c875a 100644
--- a/compiler/src/parser.py
+++ b/compiler/src/parser.py
@@ -84,14 +84,14 @@
 
 
 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 @@
     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 @@
     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 @@
 	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 @@
 	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 @@
 	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 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 @@
 
 	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 @@
 	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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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.