diff options
author | Benoit Foucher <benoit@zeroc.com> | 2015-01-07 15:11:14 +0100 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2015-01-07 15:11:14 +0100 |
commit | c126ec03755c9cea578c3b6584ed64c7ba065232 (patch) | |
tree | 453ad5f807fdca1deaa8b16ee62853b414ba1e58 /cpp/src/slice2objc | |
parent | ICE-6082 added sndBufSize and rcvBufSize to UDPEndpointInfo (diff) | |
download | ice-c126ec03755c9cea578c3b6584ed64c7ba065232.tar.bz2 ice-c126ec03755c9cea578c3b6584ed64c7ba065232.tar.xz ice-c126ec03755c9cea578c3b6584ed64c7ba065232.zip |
Added Objective-C mapping
Diffstat (limited to 'cpp/src/slice2objc')
-rw-r--r-- | cpp/src/slice2objc/Gen.cpp | 3139 | ||||
-rw-r--r-- | cpp/src/slice2objc/Gen.h | 186 | ||||
-rw-r--r-- | cpp/src/slice2objc/Main.cpp | 290 | ||||
-rw-r--r-- | cpp/src/slice2objc/Makefile | 31 |
4 files changed, 3646 insertions, 0 deletions
diff --git a/cpp/src/slice2objc/Gen.cpp b/cpp/src/slice2objc/Gen.cpp new file mode 100644 index 00000000000..763f3f5661a --- /dev/null +++ b/cpp/src/slice2objc/Gen.cpp @@ -0,0 +1,3139 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/DisableWarnings.h> +#include <IceUtil/Functional.h> +#include <Gen.h> +#include <limits> +#include <sys/stat.h> +#ifndef _WIN32 +#include <unistd.h> +#else +#include <direct.h> +#endif +#include <IceUtil/Iterator.h> +#include <IceUtil/UUID.h> +#include <Slice/Checksum.h> +#include <Slice/FileTracker.h> +#include <Slice/Util.h> +#include <string.h> + +using namespace std; +using namespace Slice; +using namespace IceUtilInternal; + +namespace +{ + +string +sliceModeToIceMode(Operation::Mode opMode) +{ + string mode; + switch(opMode) + { + case Operation::Normal: + { + mode = "ICENormal"; + break; + } + case Operation::Nonmutating: + { + mode = "ICENonmutating"; + break; + } + case Operation::Idempotent: + { + mode = "ICEIdempotent"; + break; + } + default: + { + assert(false); + break; + } + } + return mode; +} + +string +opFormatTypeToString(const OperationPtr& op) +{ + switch(op->format()) + { + case DefaultFormat: + { + return "ICEDefaultFormat"; + break; + } + case CompactFormat: + { + return "ICECompactFormat"; + break; + } + case SlicedFormat: + { + return "ICESlicedFormat"; + break; + } + default: + { + assert(false); + } + } + + return "???"; +} + +class SortParamDeclByTagFn +{ +public: + + static bool compare(const ParamDeclPtr& lhs, const ParamDeclPtr& rhs) + { + return lhs->tag() < rhs->tag(); + } +}; + +} + +Slice::ObjCVisitor::ObjCVisitor(Output& h, Output& m) : _H(h), _M(m) +{ +} + +Slice::ObjCVisitor::~ObjCVisitor() +{ +} + +void +Slice::ObjCVisitor::writeMarshalUnmarshalParams(const ParamDeclList& params, const OperationPtr& op, bool marshal, + bool reference) +{ + ParamDeclList optionals; + for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p) + { + if((*p)->optional()) + { + optionals.push_back(*p); + } + else + { + string name = reference ? "*" + fixId((*p)->name()) : fixId((*p)->name()); + writeMarshalUnmarshalCode(_M, (*p)->type(), name, marshal, true); + } + } + if(op && op->returnType()) + { + if(!op->returnIsOptional()) + { + writeMarshalUnmarshalCode(_M, op->returnType(), "ret_", marshal, true); + } + } + + optionals.sort(SortParamDeclByTagFn::compare); + bool checkReturnType = op && op->returnIsOptional(); + for(ParamDeclList::const_iterator p = optionals.begin(); p != optionals.end(); ++p) + { + if(checkReturnType && op->returnTag() < (*p)->tag()) + { + writeOptParamMarshalUnmarshalCode(_M, op->returnType(), "ret_", op->returnTag(), marshal); + checkReturnType = false; + } + string name = reference ? "*" + fixId((*p)->name()) : fixId((*p)->name()); + writeOptParamMarshalUnmarshalCode(_M, (*p)->type(), name, (*p)->tag(), marshal); + } + if(checkReturnType) + { + writeOptParamMarshalUnmarshalCode(_M, op->returnType(), "ret_", op->returnTag(), marshal); + } +} + +void +Slice::ObjCVisitor::writeDispatchAndMarshalling(const ClassDefPtr& p) +{ + string name = fixName(p); + string scoped = p->scoped(); + ClassList allBases = p->allBases(); + StringList ids; + + transform(allBases.begin(), allBases.end(), back_inserter(ids), ::IceUtil::constMemFun(&Contained::scoped)); + + StringList other; + other.push_back(p->scoped()); + other.push_back("::Ice::Object"); + other.sort(); + ids.merge(other); + ids.unique(); + + StringList::const_iterator firstIter = ids.begin(); + StringList::const_iterator scopedIter = find(ids.begin(), ids.end(), scoped); + assert(scopedIter != ids.end()); + StringList::difference_type scopedPos = IceUtilInternal::distance(firstIter, scopedIter); + + _M << sp << nl << "static NSString *" << name << "_ids__[] = "; + _M << sb; + { + StringList::const_iterator q = ids.begin(); + while(q != ids.end()) + { + _M << nl << "@\"" << *q << '"'; + if(++q != ids.end()) + { + _M << ','; + } + } + } + _M << eb << ";"; + + OperationList ops = p->operations(); + OperationList::const_iterator r; + for(r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + ContainerPtr container = op->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + assert(cl); + + string opName = getName(op); + _M << sp << nl << "+(BOOL)" << op->name() << "___:(id<" << name << ">)target_ current:(ICECurrent *)current " + << "is:(id<ICEInputStream>)is_ os:(id<ICEOutputStream>)os_"; + _M << sb; + + _M << nl << "ICEInternalCheckModeAndSelector(target_, " << sliceModeToIceMode(op->mode()) << ", @selector("; + string selector = getSelector(op); + if(!selector.empty()) + { + _M << selector << "current:"; + } + else + { + _M << opName << ":"; + } + _M << "), current);"; + + _M << nl << "ICEEncodingVersion* encoding = [is_ startEncapsulation];"; + ParamDeclList inParams; + ParamDeclList outParams; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if(!(*pli)->isOutParam()) + { + inParams.push_back(*pli); + } + else + { + outParams.push_back(*pli); + } + } + ExceptionList throws = op->throws(); + throws.sort(); + throws.unique(); + throws.sort(Slice::DerivedToBaseCompare()); + + for(ParamDeclList::const_iterator inp = inParams.begin(); inp != inParams.end(); ++inp) + { + TypePtr type = (*inp)->type(); + string name = (*inp)->name(); + _M << nl << outTypeToString(type, (*inp)->optional(), true) << " " << fixId(name); + if(!isValueType(type)) + { + _M << " = nil"; + } + _M << ";"; + } + writeMarshalUnmarshalParams(inParams, 0, false); + if(op->sendsClasses(false)) + { + _M << nl << "[is_ readPendingObjects];"; + } + _M << nl << "[is_ endEncapsulation];"; + if(!throws.empty()) + { + _M << nl << "@try"; + _M << sb; + } + for(ParamDeclList::const_iterator outp = outParams.begin(); outp != outParams.end(); ++outp) + { + TypePtr type = (*outp)->type(); + string name = (*outp)->name(); + _M << nl << inTypeToString(type, (*outp)->optional(), true) << " " << fixId(name); + if((*outp)->optional()) + { + _M << " = ICENone"; + } + _M << ";"; + } + _M << nl << "[os_ startEncapsulation:encoding format:" << opFormatTypeToString(*r) << "];"; + TypePtr returnType = op->returnType(); + if(returnType) + { + _M << nl << inTypeToString(returnType, op->returnIsOptional(), true) << " ret_ = "; + } + else + { + _M << nl; + } + string args = getServerArgs(op); + _M << "[target_ " << opName << args; + if(!args.empty()) + { + _M << " current"; + } + _M << ":current];"; + writeMarshalUnmarshalParams(outParams, op, true); + if(op->returnsClasses(false)) + { + _M << nl << "[os_ writePendingObjects];"; + } + if(!throws.empty()) + { + _M << eb; + ExceptionList::const_iterator t; + for(t = throws.begin(); t != throws.end(); ++t) + { + string exS = fixName(*t); + _M << nl << "@catch(" << exS << " *ex)"; + _M << sb; + _M << nl << "[os_ writeException:ex];"; + _M << nl << "return NO;"; + _M << eb; + } + _M << nl << "@finally"; + _M << sb; + _M << nl << "[os_ endEncapsulation];"; + _M << eb; + } + else + { + _M << nl << "[os_ endEncapsulation];"; + } + _M << nl << "return YES;"; + _M << eb; + } + + OperationList allOps = p->allOperations(); + if(!allOps.empty()) + { + map<string, string> allOpNames; + for(OperationList::const_iterator p = allOps.begin(); p != allOps.end(); ++p) + { + allOpNames.insert(make_pair((*p)->name(), fixName(ClassDefPtr::dynamicCast((*p)->container())))); + } + + allOpNames["ice_id"] = "ICEObject"; + allOpNames["ice_ids"] = "ICEObject"; + allOpNames["ice_isA"] = "ICEObject"; + allOpNames["ice_ping"] = "ICEObject"; + + map<string, string>::const_iterator q; + + _M << sp << nl << "static NSString *" << name << "_all__[] ="; + _M << sb; + q = allOpNames.begin(); + while(q != allOpNames.end()) + { + _M << nl << "@\"" << q->first << '"'; + if(++q != allOpNames.end()) + { + _M << ','; + } + } + _M << eb << ';'; + + _M << sp << nl << "-(BOOL) dispatch__:(ICECurrent *)current is:(id<ICEInputStream>)is " + << "os:(id<ICEOutputStream>)os"; + _M << sb; + _M << nl << "id target__ = [self target__];"; + _M << nl << "switch(ICEInternalLookupString(" << name << "_all__, sizeof(" << name + << "_all__) / sizeof(NSString*), current.operation))"; + _M << sb; + int i = 0; + for(q = allOpNames.begin(); q != allOpNames.end(); ++q) + { + _M << nl << "case " << i++ << ':'; + _M.inc(); + string target = (q->second == "ICEObject") ? "self" : "target__"; + _M << nl << "return [" << q->second << " " << q->first << "___:(id<" << q->second + << ">)" << target << " current:current is:is os:os];"; + _M.dec(); + } + _M << nl << "default:"; + _M.inc(); + _M << nl << "@throw [ICEOperationNotExistException operationNotExistException:"; + _M.useCurrentPosAsIndent(); + _M << "__FILE__"; + _M << nl << "line:__LINE__"; + _M << nl << "id_:current.id_"; + _M << nl << "facet:current.facet"; + _M << nl << "operation:current.operation];"; + _M.restoreIndent(); + _M.dec(); + _M << eb; + _M << eb; + } + + _M << sp << nl << "+(NSString * const*) staticIds__:(int*)count idIndex:(int*)idx"; + _M << sb; + _M << nl << "*count = sizeof(" << name << "_ids__) / sizeof(NSString *);"; + _M << nl << "*idx = " << scopedPos << ";"; + _M << nl << "return " << name << "_ids__;"; + _M << eb; +} + +string +Slice::ObjCVisitor::getName(const OperationPtr& op) const +{ + if(!op->parameters().empty()) + { + return fixId(op->name(), BaseTypeNone); + } + else + { + return fixId(op->name(), BaseTypeObject); + } +} + +string +Slice::ObjCVisitor::getSelector(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if(q == paramList.begin()) + { + result += getName(op) + ":"; + } + else + { + result += fixId((*q)->name()) + ":"; + } + } + return result; +} + +string +Slice::ObjCVisitor::getParams(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + TypePtr type = (*q)->type(); + string typeString; + if((*q)->isOutParam()) + { + typeString = outTypeToString(type, (*q)->optional(), false, true); + } + else + { + typeString = inTypeToString(type, (*q)->optional()); + } + string name = fixId((*q)->name()); + if(q != paramList.begin()) + { + result += " " + name; + } + result += ":(" + typeString + ")" + name; + } + return result; +} + +string +Slice::ObjCVisitor::getMarshalParams(const OperationPtr& op) const +{ + ParamDeclList paramList = op->parameters(); + string result; + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if(!(*q)->isOutParam()) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name()); + if(!result.empty()) + { + result += " " + name; + } + result += ":(" + inTypeToString(type, (*q)->optional()) + ")" + name; + } + } + return result; +} + +string +Slice::ObjCVisitor::getUnmarshalParams(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name()); + if(!result.empty()) + { + result += " " + name; + } + result += ":(" + outTypeToString(type, (*q)->optional(), false, true) + ")" + name; + } + } + return result; +} + +string +Slice::ObjCVisitor::getServerParams(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + TypePtr type = (*q)->type(); + string typeString; + if((*q)->isOutParam()) + { + typeString = inTypeToString(type, (*q)->optional(), false, true); + } + else + { + typeString = outTypeToString(type, (*q)->optional()); + } + string name = fixId((*q)->name()); + if(q != paramList.begin()) + { + result += " " + name; + } + result += ":(" + typeString + ")" + name; + } + return result; +} + +string +Slice::ObjCVisitor::getResponseCBSig(const OperationPtr& op) const +{ + string result; + TypePtr returnType = op->returnType(); + if(returnType) + { + result = outTypeToString(returnType, op->returnIsOptional()); + } + + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name()); + if(!result.empty()) + { + result += ", "; + } + result += outTypeToString(type, (*q)->optional()); + } + } + return "void(^)(" + result + ")"; +} + +string +Slice::ObjCVisitor::getArgs(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string name = fixId((*q)->name()); + if(q != paramList.begin()) + { + result += " " + name; + } + result += ":" + name; + } + return result; +} + +string +Slice::ObjCVisitor::getMarshalArgs(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if(!(*q)->isOutParam()) + { + string name = fixId((*q)->name()); + if(!result.empty()) + { + result += " " + name; + } + result += ":" + name; + } + } + return result; +} + +string +Slice::ObjCVisitor::getUnmarshalArgs(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + string name = fixId((*q)->name()); + if(!result.empty()) + { + result += " " + name; + } + result += ":" + name; + } + } + return result; +} + +string +Slice::ObjCVisitor::getServerArgs(const OperationPtr& op) const +{ + string result; + ParamDeclList paramList = op->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string name = fixId((*q)->name()); + if(q != paramList.begin()) + { + result += " " + name; + } + result += ":"; + if((*q)->isOutParam()) + { + result += "&"; + } + result += name; + } + return result; +} + +Slice::Gen::Gen(const string& name, const string& base, const string& include, const vector<string>& includePaths, + const string& dir) + : _base(base), + _include(include), + _includePaths(includePaths) +{ + for(vector<string>::iterator p = _includePaths.begin(); p != _includePaths.end(); ++p) + { + *p = fullPath(*p); + } + + string::size_type pos = _base.find_last_of("/\\"); + if(pos != string::npos) + { + _base.erase(0, pos + 1); + } + + string fileH = _base + ".h"; + string fileM = _base + ".m"; + string fileImplH = _base + "I.h"; + string fileImplM = _base + "I.m"; + + if(!dir.empty()) + { + fileH = dir + '/' + fileH; + fileM = dir + '/' + fileM; + fileImplH = dir + '/' + fileImplH; + fileImplM = dir + '/' + fileImplM; + } + + _H.open(fileH.c_str()); + if(!_H) + { + ostringstream os; + os << "cannot open `" << fileH << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addFile(fileH); + printHeader(_H); + _H << nl << "// Generated from file `" << _base << ".ice'"; + + _H << sp << nl << "#import <objc/Ice/Config.h>"; + _H << nl << "#import <objc/Ice/Proxy.h>"; + _H << nl << "#import <objc/Ice/Object.h>"; + _H << nl << "#import <objc/Ice/Current.h>"; + _H << nl << "#import <objc/Ice/Exception.h>"; + _H << nl << "#import <objc/Ice/Stream.h>"; + + _M.open(fileM.c_str()); + if(!_M) + { + ostringstream os; + os << "cannot open `" << fileM << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addFile(fileM); + printHeader(_M); + _M << nl << "// Generated from file `" << _base << ".ice'"; +} + +Slice::Gen::~Gen() +{ + if(_H.isOpen()) + { + _H << '\n'; + _M << '\n'; + } +} + +bool +Slice::Gen::operator!() const +{ + if(!_H || !_M) + { + return true; + } + return false; +} + +void +Slice::Gen::generate(const UnitPtr& p) +{ + ObjCGenerator::validateMetaData(p); + + _M << nl << "\n#import <objc/Ice/LocalException.h>"; + _M << nl << "#import <objc/Ice/Stream.h>"; + if(p->hasContentsWithMetaData("preserve-slice")) + { + _H << "\n#import <objc/Ice/SlicedData.h>"; + } + _M << nl << "#import <"; + if(!_include.empty()) + { + _M << _include << "/"; + } + _M << _base << ".h>"; + + // Necessary for objc_getClass use when marshalling/unmarshalling proxies. + _M << nl << "#import <objc/runtime.h>"; + + _M << nl; + + StringList includes = p->includeFiles(); + for(StringList::const_iterator q = includes.begin(); q != includes.end(); ++q) + { + static const string headerDirPrefix = "objc:header-dir:"; + DefinitionContextPtr dc = p->findDefinitionContext(*q); + assert(dc); + string meta = dc->findMetaData(headerDirPrefix); + string headerDir; + if(meta.size() > headerDirPrefix.size()) + { + headerDir = meta.substr(headerDirPrefix.size()); + } + _H << "\n#import <"; + if(!headerDir.empty()) + { + _H << headerDir << "/"; + } + _H << changeInclude(*q, _includePaths) << ".h>"; + } + + UnitVisitor unitVisitor(_H, _M); + p->visit(&unitVisitor, false); + + ObjectDeclVisitor objectDeclVisitor(_H, _M); + p->visit(&objectDeclVisitor, false); + + ProxyDeclVisitor proxyDeclVisitor(_H, _M); + p->visit(&proxyDeclVisitor, false); + + TypesVisitor typesVisitor(_H, _M); + p->visit(&typesVisitor, false); + + ProxyVisitor proxyVisitor(_H, _M); + p->visit(&proxyVisitor, false); + + DelegateMVisitor delegateMVisitor(_H, _M); + p->visit(&delegateMVisitor, false); + + HelperVisitor HelperVisitor(_H, _M); + p->visit(&HelperVisitor, false); +} + +void +Slice::Gen::closeOutput() +{ + _H.close(); + _M.close(); +} + +void +Slice::Gen::printHeader(Output& o) +{ + static const char* header = +"// **********************************************************************\n" +"//\n" +"// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved.\n" +"//\n" +"// This copy of Ice is licensed to you under the terms described in the\n" +"// ICE_LICENSE file included in this distribution.\n" +"//\n" +"// **********************************************************************\n" + ; + + o << header; + o << "\n// Ice version " << ICE_STRING_VERSION; +} + +Slice::Gen::UnitVisitor::UnitVisitor(Output& H, Output& M) : + ObjCVisitor(H, M) +{ +} + +bool +Slice::Gen::UnitVisitor::visitModuleStart(const ModulePtr& p) +{ + string dummy; + if(p->findMetaData("objc:prefix", dummy)) + { + _prefixes.push_back(modulePrefix(p)); + } + return true; +} + +void +Slice::Gen::UnitVisitor::visitUnitEnd(const UnitPtr& unit) +{ + string uuid = IceUtil::generateUUID(); + for(string::size_type pos = 0; pos < uuid.size(); ++pos) + { + if(!isalnum(uuid[pos])) + { + uuid[pos] = '_'; + } + } + + if(!_prefixes.empty()) + { + _M << sp << nl << "@implementation ICEInternalPrefixTable(C" << uuid << ")"; + _M << nl << "-(void)addPrefixes_C" << uuid << ":(NSMutableDictionary*)prefixTable"; + _M << sb; + for(vector<Slice::ObjCGenerator::ModulePrefix>::const_iterator p = _prefixes.begin(); p != _prefixes.end(); ++p) + { + _M << nl << "[prefixTable setObject:@\"" << p->name << "\" forKey:@\"" << p->m->scoped() << "\"];"; + } + _M << eb; + _M << nl << "@end"; + } +} + +Slice::Gen::ObjectDeclVisitor::ObjectDeclVisitor(Output& H, Output& M) + : ObjCVisitor(H, M) +{ +} + +void +Slice::Gen::ObjectDeclVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + _H << sp << nl << "@class " << fixName(p) << ";"; + _H << nl << "@protocol " << fixName(p) << ";"; +} + +Slice::Gen::ProxyDeclVisitor::ProxyDeclVisitor(Output& H, Output& M) + : ObjCVisitor(H, M) +{ +} + +void +Slice::Gen::ProxyDeclVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + _H << sp << nl << "@class " << fixName(p) << "Prx;"; + _H << nl << "@protocol " << fixName(p) << "Prx;"; +} + +Slice::Gen::TypesVisitor::TypesVisitor(Output& H, Output& M) + : ObjCVisitor(H, M) +{ +} + +bool +Slice::Gen::TypesVisitor::visitModuleStart(const ModulePtr& p) +{ + string suffix; + StringList names = splitScopedName(p->scoped()); + for(StringList::const_iterator i = names.begin(); i != names.end(); ++i) + { + if(i != names.begin()) + { + suffix += "_"; + } + suffix += *i; + } + string symbol = "ICE_MODULE_PREFIX_"; + symbol += suffix; + return true; +} + +void +Slice::Gen::TypesVisitor::visitModuleEnd(const ModulePtr&) +{ +} + +bool +Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string name = fixName(p); + ClassList bases = p->bases(); + + _H << sp << nl << "@protocol " << name; + if(!bases.empty()) + { + _H << " <"; + for(ClassList::const_iterator i = bases.begin(); i != bases.end(); ++i) + { + string baseName = fixName(*i); + if(i != bases.begin()) + { + _H << ", "; + } + _H << baseName; + } + _H << ">"; + } + + _M << sp << nl << "@implementation " << name; + + return true; +} + +void +Slice::Gen::TypesVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + string name = fixName(p); + ClassList bases = p->bases(); + bool basePreserved = p->inheritsMetaData("preserve-slice"); + bool preserved = p->hasMetaData("preserve-slice"); + bool hasBaseClass = !bases.empty() && !bases.front()->isInterface(); + string baseName = hasBaseClass ? fixName(bases.front()) : "ICEObject"; + DataMemberList baseDataMembers; + if(hasBaseClass) + { + baseDataMembers = bases.front()->allDataMembers(); + } + DataMemberList dataMembers = p->dataMembers(); + DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + DataMemberList allDataMembers = p->allDataMembers(); + + _H << nl << "@end"; + + _H << sp << nl << "@interface " << name << " : " << baseName; + + if(!dataMembers.empty() || (preserved && !basePreserved)) + { + // + // Data member declarations. + // + _H << sb; + + if(!dataMembers.empty()) + { + writeMembers(dataMembers, BaseTypeObject); + } + + if(preserved && !basePreserved) + { + _H << nl << "id<ICESlicedData> slicedData__;"; + } + + _H << eb; + _H << sp; + + _M << sp; + } + + // + // @property and @synthesize for each data member. + // + writeProperties(dataMembers, BaseTypeObject); + writeSynthesize(dataMembers, BaseTypeObject); + + // + // Constructor. + // + if(!dataMembers.empty()) + { + _H << sp; + } + if(!p->isInterface() && !dataMembers.empty()) + { + if(p->hasDefaultValues()) + { + _H << nl << "-(id) init;"; + _M << sp << nl << "-(id) init"; + _M << sb; + _M << nl << "self = [super init];"; + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + writeMemberDefaultValueInit(dataMembers, BaseTypeObject); + _M << nl << "return self;"; + _M << eb; + } + _H << nl << "-(id) init"; + _M << sp << nl << "-(id) init"; + writeMemberSignature(allDataMembers, BaseTypeObject, Other); + _H << ";"; + _M << sb; + _M << nl << "self = [super init"; + writeMemberCall(baseDataMembers, BaseTypeObject, Other, WithEscape); + _M << "];"; + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + writeMemberInit(dataMembers, BaseTypeObject); + _M << nl << "return self;"; + _M << eb; + } + + // + // Convenience constructors. + // + if(!allDataMembers.empty()) + { + string lowerCaseName = fixId(p->name()); + *(lowerCaseName.begin()) = tolower(*lowerCaseName.begin()); + + _H << nl << "+(id) " << lowerCaseName; + _M << sp << nl << "+(id) " << lowerCaseName; + writeMemberSignature(allDataMembers, BaseTypeObject, Other); + _H << ";"; + _M << sb; + + // + // The cast avoids a compiler warning that is emitted if different structs + // have members with the same name but different types. + // + _M << nl << name << " *s__ = [(" << name << " *)[" << name << " alloc] init"; + writeMemberCall(allDataMembers, BaseTypeObject, Other, WithEscape); + _M << "];"; + + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "[s__ autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + + _M << nl << "return s__;"; + _M << eb; + + _H << nl << "+(id) " << lowerCaseName << ";"; + _M << sp << nl << "+(id) " << lowerCaseName; + _M << sb; + _M << nl << name << " *s__ = [[" << name << " alloc] init];"; + + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "[s__ autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + + _M << nl << "return s__;"; + _M << eb; + } + + if(!p->isInterface()) + { + // + // copyWithZone and dealloc + // + if(!dataMembers.empty()) + { + _M << sp << nl << "-(id) copyWithZone:(NSZone *)zone_p"; + _M << sb; + _M << nl << "return [(" << name << " *)[[self class] allocWithZone:zone_p] init"; + writeMemberCall(allDataMembers, BaseTypeObject, Other, NoEscape); + _M << "];"; + _M << eb; + _H << nl << "// This class also overrides copyWithZone:."; + + writeMemberDealloc(dataMembers, BaseTypeObject, preserved && !basePreserved); + } + } + + // + // Setter, has, clear selectors for optionals + // + writeOptionalDataMemberSelectors(dataMembers, BaseTypeObject); + + // + // If the class uses a compact id we generate a +load method to register the compact id + // with the compact id resolver. + // + if(p->compactId() >= 0) + { + _M << sp << nl << "+(void) load"; + _M << sb; + _M << nl << "[CompactIdMapHelper registerClass:@\"" << p->scoped() << "\" value:" << p->compactId() << "];"; + _M << eb; + } + + // + // Operations + // + OperationList ops = p->operations(); + OperationList::const_iterator r; + for(r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = *r; + _H << nl << "+(BOOL)" << op->name() << "___:(id<" << name + << ">)target current:(ICECurrent *)current " + << "is:(id<ICEInputStream>)is_ os:(id<ICEOutputStream>)os_;"; + } + + _M << sp << nl << "+(id)objectWithDelegate:(id)delegate"; + _M << sb; + _M.zeroIndent(); + _M << sp << nl << "#if defined(__clang__) && __has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "return [[" << name << " alloc] initWithDelegate:delegate];"; + _M.zeroIndent(); + _M << nl << "#else"; + _M.restoreIndent(); + _M << nl << "return [[[" << name << " alloc] initWithDelegate:delegate] autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + _M << eb; + + // + // Marshaling/unmarshaling + // + + _M << sp << nl << "-(void) writeImpl__:(id<ICEOutputStream>)os_"; + _M << sb; + _M << nl << "[os_ startSlice:@\"" << p->scoped() << "\" compactId: " << p->compactId() << " lastSlice:" + << (!hasBaseClass ? "YES" : "NO") << "];"; + writeMemberMarshal(dataMembers, optionalMembers, BaseTypeObject); + _M << nl << "[os_ endSlice];"; + if(hasBaseClass) + { + _M << nl << "[super writeImpl__:os_];"; + } + _M << eb; + + _H << nl << "@end"; + + _M << sp << nl << "-(void) readImpl__:(id<ICEInputStream>)is_"; + _M << sb; + _M << nl << "[is_ startSlice];"; + writeMemberUnmarshal(dataMembers, optionalMembers, BaseTypeObject); + _M << nl << "[is_ endSlice];"; + if(hasBaseClass) + { + _M << nl << "[super readImpl__:is_];"; + } + _M << eb; + + writeDispatchAndMarshalling(p); + + if(preserved && !basePreserved) + { + _M << nl << "-(void) write__:(id<ICEOutputStream>)os"; + _M << sb; + _M << nl << "[os startObject:slicedData__];"; + _M << nl << "[self writeImpl__:os];"; + _M << nl << "[os endObject];"; + _M << eb; + + _M << nl << "-(void) read__:(id<ICEInputStream>)is"; + _M << sb; + _M << nl << "[is startObject];"; + _M << nl << "[self readImpl__:is];"; + _M << nl << "slicedData__ = [is endObject:YES];"; + _M << eb; + } + + _M << nl << "@end"; +} + +void +Slice::Gen::TypesVisitor::visitOperation(const OperationPtr& p) +{ + string name = getName(p); + TypePtr returnType = p->returnType(); + string retString = typeToString(returnType); + string params = getServerParams(p); + + + _H << nl << "-(" << inTypeToString(returnType, p->returnIsOptional()) << ") " << name << params; + if(!params.empty()) + { + _H << " current"; + } + _H << ":(ICECurrent *)current;"; +} + +void +Slice::Gen::TypesVisitor::visitSequence(const SequencePtr& p) +{ + string prefix = moduleName(findModule(p)); + string name = fixName(p); + + if(isValueType(p->type())) + { + _H << sp << nl << "typedef NSData " << name << ";"; + _H << nl << "typedef NSMutableData " << prefix << "Mutable" << p->name() << ";"; + } + else + { + _H << sp << nl << "typedef NSArray " << name << ";"; + _H << nl << "typedef NSMutableArray " << prefix << "Mutable" << p->name() << ";"; + } +} + +bool +Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + string name = fixName(p); + ExceptionPtr base = p->base(); + DataMemberList dataMembers = p->dataMembers(); + bool basePreserved = p->inheritsMetaData("preserve-slice"); + bool preserved = p->hasMetaData("preserve-slice"); + + _H << sp; + + _H << nl << "@interface " << name << " : "; + if(base) + { + _H << fixName(base); + } + else + { + _H << (p->isLocal() ? "ICELocalException" : "ICEUserException"); + } + if(!dataMembers.empty() || (preserved && !basePreserved)) + { + _H << sb; + } + + _M << sp << nl << "@implementation " << name; + + return true; +} + +void +Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) +{ + string name = fixName(p); + + string lowerCaseName = fixId(p->name()); + *(lowerCaseName.begin()) = tolower(*lowerCaseName.begin()); + bool basePreserved = p->inheritsMetaData("preserve-slice"); + bool preserved = p->hasMetaData("preserve-slice"); + DataMemberList dataMembers = p->dataMembers(); + DataMemberList optionalMembers = p->orderedOptionalDataMembers(); + DataMemberList allDataMembers = p->allDataMembers(); + DataMemberList::const_iterator q; + + DataMemberList baseDataMembers; + if(p->base()) + { + baseDataMembers = p->base()->allDataMembers(); + } + + if(!dataMembers.empty() || (preserved && !basePreserved)) + { + // + // Data member declarations. + // + if(!dataMembers.empty()) + { + writeMembers(dataMembers, BaseTypeException); + } + + if(preserved && !basePreserved) + { + _H << nl << "id<ICESlicedData> slicedData__;"; + } + + _H << eb; + _H << sp; + _M << sp; + + // + // @property and @synthesize for each data member. + // + if(!dataMembers.empty()) + { + writeProperties(dataMembers, BaseTypeException); + writeSynthesize(dataMembers, BaseTypeException); + } + _H << sp; + } + + // + // ice_name + // + _H << nl << "-(NSString *) ice_name;"; + _M << sp << nl << "-(NSString *) ice_name"; + _M << sb; + _M << nl << "return @\"" << p->scoped().substr(2) << "\";"; + _M << eb; + + // + // Constructors. + // + if(p->isLocal() && !dataMembers.empty()) + { + _H << nl << "-(id) init:(const char*)file__p line:(int)line__p;"; + _M << sp << nl << "-(id) init:(const char*)file__p line:(int)line__p"; + _M << sb; + _M << nl << "self = [super init:file__p line:line__p];"; + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + _M << nl << "return self;"; + _M << eb; + } + if(!dataMembers.empty()) + { + if(!p->base() || p->hasDefaultValues()) + { + _H << sp << nl << "-(id) init;"; + _M << sp << nl << "-(id) init"; + _M << sb; + _M << nl << "self = "; + if(!p->base()) + { + _M << "[super initWithName:[self ice_name] reason:nil userInfo:nil];"; + } + else + { + _M << nl << "[super init];"; + } + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + if(p->hasDefaultValues()) + { + writeMemberDefaultValueInit(dataMembers, BaseTypeObject); + } + _M << nl << "return self;"; + _M << eb; + } + + _H << nl << "-(id) init"; + _M << sp << nl << "-(id) init"; + writeMemberSignature(allDataMembers, BaseTypeException, p->isLocal() ? LocalException : Other); + _H << ";"; + _M << sb; + _M << nl << "self = "; + if(!p->base()) + { + _M << nl << "[super initWithName:[self ice_name] reason:nil userInfo:nil];"; + } + else + { + _M << nl << "[super init"; + if(p->isLocal()) + { + _M << ":file__p line:line__p "; + } + writeMemberCall(baseDataMembers, BaseTypeException, p->isLocal() ? LocalException : Other, WithEscape); + _M << "];"; + } + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + if(!dataMembers.empty()) + { + writeMemberInit(dataMembers, BaseTypeException); + } + _M << nl << "return self;"; + _M << eb; + } + + // + // Convenience constructors. + // + _H << nl << "+(id) " << lowerCaseName; + _M << sp << nl << "+(id) " << lowerCaseName; + writeMemberSignature(allDataMembers, BaseTypeException, p->isLocal() ? LocalException : Other); + _H << ";"; + + // + // The cast avoids a compiler warning that is emitted if different exceptions + // have members with the same name but different types. + // + _M << sb; + _M << nl << name << " *s__ = [(" << name << " *)[" << name << " alloc] init"; + if(p->isLocal()) + { + _M << ":file__p line:line__p"; + } + writeMemberCall(allDataMembers, BaseTypeException, p->isLocal() ? LocalException : Other, WithEscape); + _M << "];"; + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "[s__ autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + _M << nl << "return s__;"; + _M << eb; + + if(!allDataMembers.empty()) + { + _H << nl << "+(id) " << lowerCaseName; + _M << sp << nl << "+(id) " << lowerCaseName; + if(p->isLocal()) + { + _H << ":(const char*)file__p line:(int)line__p"; + _M << ":(const char*)file__p line:(int)line__p"; + } + _H << ";"; + _M << sb; + _M << nl << name << " *s__ = [[" << name << " alloc] init"; + if(p->isLocal()) + { + _M << ":file__p line:line__p"; + } + _M << "];"; + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "[s__ autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + _M << nl << "return s__;"; + _M << eb; + } + + // + // copyWithZone and dealloc + // + if(!dataMembers.empty()) + { + _M << sp << nl << "-(id) copyWithZone:(NSZone *)zone_p"; + _M << sb; + _M << nl << "return [(" << name << " *)[[self class] allocWithZone:zone_p] init"; + if(p->isLocal()) + { + _M << ":file line:line"; + } + writeMemberCall(allDataMembers, BaseTypeException, p->isLocal() ? LocalException : Other, NoEscape); + _M << "];"; + _M << eb; + _H << nl << "// This class also overrides copyWithZone:."; + + writeMemberDealloc(dataMembers, BaseTypeException, preserved && !basePreserved); + } + + // + // Setter, has, clear selectors for optionals + // + writeOptionalDataMemberSelectors(dataMembers, BaseTypeObject); + + // + // Marshaling/unmarshaling + // + ExceptionPtr base = p->base(); + if(!p->allClassDataMembers().empty()) + { + if(!base || (base && !base->usesClasses(false))) + { + _M << sp << nl << "-(BOOL) usesClasses__"; + _M << sb; + _M << nl << "return YES;"; + _M << eb; + } + } + + if(!p->isLocal()) + { + _M << sp << nl << "-(void) writeImpl__:(id<ICEOutputStream>)os_"; + _M << sb; + _M << nl << "[os_ startSlice:@\"" << p->scoped() << "\" compactId:-1 lastSlice:" + << (!base ? "YES" : "NO") << "];"; + writeMemberMarshal(dataMembers, optionalMembers, BaseTypeException); + _M << nl << "[os_ endSlice];"; + if(base) + { + _M << nl << "[super writeImpl__:os_];"; + } + _M << eb; + + _M << sp << nl << "-(void) readImpl__:(id<ICEInputStream>)is_"; + _M << sb; + _M << nl << "[is_ startSlice];"; + writeMemberUnmarshal(dataMembers, optionalMembers, BaseTypeException); + _M << nl << "[is_ endSlice];"; + if(base) + { + _M << nl << "[super readImpl__:is_];"; + } + _M << eb; + + if(preserved && !basePreserved) + { + _M << nl << nl << "-(void) write__:(id<ICEOutputStream>)os"; + _M << sb; + _M << nl << "[os startException:slicedData__];"; + _M << nl << "[self writeImpl__:os];"; + _M << nl << "[os endException];"; + _M << eb; + + _M << nl << nl << "-(void) read__:(id<ICEInputStream>)is"; + _M << sb; + _M << nl << "[is startException];"; + _M << nl << "[self readImpl__:is];"; + _M << nl << "slicedData__ = [is endException:YES];"; + _M << eb; + } + } + + _H << nl << "@end"; + _M << nl << "@end"; +} + +bool +Slice::Gen::TypesVisitor::visitStructStart(const StructPtr& p) +{ + string name = fixName(p); + + _H << sp; + + _H << nl << "@interface " << name << " : NSObject <NSCopying>"; + _H << sb; + _H << nl << "@private"; + _H.inc(); + + _M << sp << nl << "@implementation " << name << sp; + + return true; +} + +void +Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) +{ + string name = fixName(p); + DataMemberList dataMembers = p->dataMembers(); + DataMemberList::const_iterator q; + + // + // Data member declarations. + // + writeMembers(dataMembers, BaseTypeObject); + + _H.dec(); + _H << eb; + + _H << sp; + + // + // @property and @synthesize for each data member. + // + writeProperties(dataMembers, BaseTypeObject); + writeSynthesize(dataMembers, BaseTypeObject); + + // + // Constructor. + // + if(p->hasDefaultValues()) + { + _H << sp << nl << "-(id) init;"; + _M << sp << nl << "-(id) init"; + _M << sb; + _M << nl << "self = [super init];"; + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + writeMemberDefaultValueInit(dataMembers, BaseTypeObject); + _M << nl << "return self;"; + _M << eb; + } + _H << sp << nl << "-(id) init"; + _M << sp << nl << "-(id) init"; + writeMemberSignature(dataMembers, BaseTypeObject, Other); + _H << ";"; + _M << sb; + _M << nl << "self = [super init];"; + _M << nl << "if(!self)"; + _M << sb; + _M << nl << "return nil;"; + _M << eb; + writeMemberInit(dataMembers, BaseTypeObject); + _M << nl << "return self;"; + _M << eb; + + // + // Convenience constructor. + // + string lowerCaseName = fixId(p->name()); + *(lowerCaseName.begin()) = tolower(*lowerCaseName.begin()); + + _H << nl << "+(id) " << lowerCaseName; + _M << sp << nl << "+(id) " << lowerCaseName; + writeMemberSignature(dataMembers, BaseTypeObject, Other); + _H << ";"; + _M << sb; + + // + // The cast avoids a compiler warning that is emitted if different structs + // have members with the same name but different types. + // + _M << nl << name << " *s__ = [(" << name << "* )[" << name << " alloc] init"; + writeMemberCall(dataMembers, BaseTypeObject, Other, WithEscape); + _M << "];"; + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "[s__ autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + _M << nl << "return s__;"; + _M << eb; + + _H << nl << "+(id) " << lowerCaseName << ";"; + _M << sp << nl << "+(id) " << lowerCaseName; + _M << sb; + _M << nl << name << " *s__ = [[" << name << " alloc] init];"; + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "[s__ autorelease];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + _M << nl << "return s__;"; + _M << eb; + + // + // copyWithZone + // + _M << sp << nl << "-(id) copyWithZone:(NSZone *)zone_p"; + _M << sb; + _M << nl << "return [(" << name << " *)[[self class] allocWithZone:zone_p] init"; + writeMemberCall(dataMembers, BaseTypeObject, Other, NoEscape); + _M << "];"; + _M << eb; + + // + // hash + // + writeMemberHashCode(dataMembers, BaseTypeObject); + + // + // isEqual + // + _M << sp << nl << "-(BOOL) isEqual:(id)o_"; + _M << sb; + _M << nl << "if(self == o_)"; + _M << sb; + _M << nl << "return YES;"; + _M << eb; + _M << nl << "if(!o_ || ![o_ isKindOfClass:[self class]])"; + _M << sb; + _M << nl << "return NO;"; + _M << eb; + writeMemberEquals(dataMembers, BaseTypeObject); + _M << eb; + + _H << nl << "// This class also overrides copyWithZone:, hash, and isEqual:"; + + // + // dealloc + // + writeMemberDealloc(dataMembers, BaseTypeObject); + + // + // Marshaling/unmarshaling + // + _H << nl << "-(void) write__:(id<ICEOutputStream>)os_;"; + _H << nl << "-(void) read__:(id<ICEInputStream>)is_;"; + + _M << sp << nl << "-(void) write__:(id<ICEOutputStream>)os_"; + _M << sb; + writeMemberMarshal(dataMembers, DataMemberList(), BaseTypeObject); + _M << eb; + + _M << sp << nl << "-(void) read__:(id<ICEInputStream>)is_"; + _M << sb; + writeMemberUnmarshal(dataMembers, DataMemberList(), BaseTypeObject); + _M << eb; + + _H << nl << "@end"; + _M << nl << "@end"; +} + +void +Slice::Gen::TypesVisitor::visitDictionary(const DictionaryPtr& p) +{ + string prefix = moduleName(findModule(p)); + string name = fixName(p); + + _H << sp << nl << "typedef NSDictionary " << name << ";"; + _H << nl << "typedef NSMutableDictionary " << prefix << "Mutable" << p->name() << ";"; +} + +void +Slice::Gen::TypesVisitor::visitEnum(const EnumPtr& p) +{ + string name = fixName(p); + EnumeratorList enumerators = p->getEnumerators(); + _H << sp; + + // + // Check if any of the enumerators were assigned an explicit value. + // + const bool explicitValue = p->explicitValue(); + + _H << nl << "typedef enum : ICEInt"; + _H << sb; + EnumeratorList::const_iterator en = enumerators.begin(); + while(en != enumerators.end()) + { + _H << nl << fixName(*en); + // + // If any of the enumerators were assigned an explicit value, we emit + // an explicit value for *all* enumerators. + // + if(explicitValue) + { + _H << " = " << int64ToString((*en)->value()); + } + if(++en != enumerators.end()) + { + _H << ','; + } + } + _H << eb << " " << name << ";"; +} + +void +Slice::Gen::TypesVisitor::visitConst(const ConstPtr& p) +{ + _H << sp; + if(isString(p->type())) + { + _H << nl << "static NSString * const"; + } + else + { + _H << nl << "static const " << typeToString(p->type()); + } + _H << " " << fixName(p) << " = "; + writeConstantValue(_H, p->type(), p->value()); + _H << ';'; +} + +void +Slice::Gen::TypesVisitor::writeConstantValue(IceUtilInternal::Output& out, const TypePtr& type, const string& val) const +{ + if(isString(type)) + { + // + // Expand strings into the basic source character set. We can't use isalpha() and the like + // here because they are sensitive to the current locale. + // + static const string basicSourceChars = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "_{}[]#()<>%:;.?*+-/^&|~!=,\\\"' "; + static const set<char> charSet(basicSourceChars.begin(), basicSourceChars.end()); + + out << "@\""; // Opening @" + + for(string::const_iterator c = val.begin(); c != val.end(); ++c) + { + if(charSet.find(*c) == charSet.end()) + { + unsigned char uc = *c; // char may be signed, so make it positive + ostringstream s; + s << "\\"; // Print as octal if not in basic source character set + s.width(3); + s.fill('0'); + s << oct; + s << static_cast<unsigned>(uc); + out << s.str(); + } + else + { + out << *c; // Print normally if in basic source character set + } + } + + out << "\""; // Closing " + } + else + { + EnumPtr ep = EnumPtr::dynamicCast(type); + if(ep) + { + out << moduleName(findModule(ep)) << val; + } + else + { + if(val == "true") + { + out << "YES"; + } + else if(val == "false") + { + out << "NO"; + } + else + { + out << val; + } + } + } +} + +void +Slice::Gen::TypesVisitor::writeMembers(const DataMemberList& dataMembers, int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name(), baseType); + + _H << nl << typeToString(type) << " "; + if(mapsToPointerType(type)) + { + _H << "*"; + } + _H << name << ";"; + + if((*q)->optional()) + { + _H << nl << "BOOL has_" << name << "__;"; + } + } +} + +void +Slice::Gen::TypesVisitor::writeMemberSignature(const DataMemberList& dataMembers, int baseType, + ContainerType ct) const +{ + if(ct == LocalException) + { + _H << ":(const char*)file__p line:(int)line__p"; + _M << ":(const char*)file__p line:(int)line__p"; + } + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + string typeString = inTypeToString(type, (*q)->optional()); + string name = fixId((*q)->name(), baseType); + + if(q != dataMembers.begin() || ct == LocalException) + { + _H << " " << name; + _M << " " << name; + } + _H << ":(" << typeString << ")" << fixId((*q)->name()); + _M << ":(" << typeString << ")" << fixId((*q)->name()) << "_p"; + } +} + +void +Slice::Gen::TypesVisitor::writeMemberCall(const DataMemberList& dataMembers, int baseType, + ContainerType ct, Escape esc) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + string name = (*q)->name(); + + if(q != dataMembers.begin() || ct == LocalException) + { + _M << " " << fixId(name, baseType); + } + + name = esc == NoEscape ? fixId(name, baseType) : fixId(name); + if(esc == NoEscape) + { + if((*q)->optional()) + { + if(isValueType((*q)->type())) + { + _M << ":" << "(self->has_" << name << "__ ? @(self->" << name << ") : ICENone)"; + } + else + { + _M << ":" << "(self->has_" << name << "__ ? self->" << name << " : ICENone)"; + } + } + else + { + _M << ":" << name; + } + } + else + { + _M << ":" << name << "_p"; + } + } +} + +void +Slice::Gen::TypesVisitor::writeMemberDefaultValueInit(const DataMemberList& dataMembers, int baseType) const +{ + for(DataMemberList::const_iterator p = dataMembers.begin(); p != dataMembers.end(); ++p) + { + if((*p)->defaultValueType()) + { + string name = fixId((*p)->name(), baseType); + if((*p)->optional()) + { + _M << nl << "self->has_" << name << "__ = YES;"; + } + _M << nl << "self->" << name << " = "; + writeConstantValue(_M, (*p)->type(), (*p)->defaultValue()); + _M << ";"; + } + } +} + +void +Slice::Gen::TypesVisitor::writeMemberInit(const DataMemberList& dataMembers, int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name()); + if((*q)->optional()) + { + if(isValueType(type)) + { + _M << nl << "self->has_" << name << "__ = [ICEOptionalGetter " << getOptionalHelperGetter(type) << ":"; + _M << name << "_p value:&self->" << fixId((*q)->name(), baseType) << "];"; + } + else + { + _M << nl << "self->has_" << name << "__ = [ICEOptionalGetter getRetained:"; + _M << name << "_p value:&self->" << fixId((*q)->name(), baseType); + _M << " type:[" << typeToObjCTypeString(type) << " class]];"; + } + } + else + { + if(isValueType(type)) + { + _M << nl << "self->" << fixId((*q)->name(), baseType) << " = " << name << "_p;"; + } + else + { + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && __has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "self->" << fixId((*q)->name(), baseType) << " = " << name << "_p;"; + _M.zeroIndent(); + _M << nl << "#else"; + _M.restoreIndent(); + _M << nl << "self->" << fixId((*q)->name(), baseType) << " = [" << name << "_p retain];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + } + } + } +} + +void +Slice::Gen::TypesVisitor::writeProperties(const DataMemberList& dataMembers, int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name(), baseType); + + string typeString = typeToString(type); + bool isValue = isValueType(type); + + _H << nl << "@property(nonatomic, "; + if(isValue) + { + _H << "assign"; + } + else + { + _H << "ICE_STRONG_ATTR"; + } + _H << ") " << typeString << " "; + if(mapsToPointerType(type)) + { + _H << "*"; + } + _H << name << ";"; + } +} + +void +Slice::Gen::TypesVisitor::writeSynthesize(const DataMemberList& dataMembers, int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + string name = fixId((*q)->name(), baseType); + _M << nl << "@synthesize " << name << ";"; + } +} + +void +Slice::Gen::TypesVisitor::writeOptionalDataMemberSelectors(const DataMemberList& dataMembers, int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + if(!(*q)->optional()) + { + continue; + } + + TypePtr type = (*q)->type(); + string typeString = inTypeToString(type, false); + + string name = fixId((*q)->name(), baseType); + + string capName = (*q)->name(); + capName[0] = toupper(static_cast<unsigned char>(capName[0])); + + _H << nl << "-(void)set" << capName << ":(" << typeString << ")" << name << "_p;"; + + _M << nl << "-(void)set" << capName << ":(" << typeString << ")" << name << "_p"; + _M << sb; + _M << nl << "self->has_" << name << "__ = YES;"; + bool isValue = isValueType(type); + if(isValue) + { + _M << nl << "self->" << name << " = " << name << "_p;"; + } + else + { + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && __has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "self->" << name << " = " << name << "_p;"; + _M.zeroIndent(); + _M << nl << "#else"; + _M.restoreIndent(); + _M << nl << "[self->" << name << " release];"; + _M << nl << "self->" << name << " = [" << name << "_p retain];"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + } + _M << eb; + + _H << nl << "-(BOOL)has" << capName << ";"; + _M << nl << "-(BOOL)has" << capName; + _M << sb; + _M << nl << "return self->has_" << name << "__;"; + _M << eb; + + _H << nl << "-(void)clear" << capName << ";"; + _M << nl << "-(void)clear" << capName; + _M << sb; + _M << nl << "self->has_" << name << "__ = NO;"; + if(!isValue) + { + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && __has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "self->" << name << " = nil;"; + _M.zeroIndent(); + _M << nl << "#else"; + _M.restoreIndent(); + _M << nl << "[self->" << name << " release];"; + _M << nl << "self->" << name << " = nil;"; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + } + _M << eb; + } +} + +void +Slice::Gen::TypesVisitor::writeMemberHashCode(const DataMemberList& dataMembers, int baseType) const +{ + _M << sp << nl << "-(NSUInteger) hash"; + _M << sb; + _M << nl << "NSUInteger h_ = 5381;"; + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name(), baseType); + + _M << nl << "h_ = ((h_ << 5) + h_) ^ "; + if(isValueType(type)) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + if(builtin->kind() == Builtin::KindFloat || builtin->kind() == Builtin::KindDouble) + { + _M << "(2654435761u * (uint)" << name << ");"; + } + else + { + _M << "(2654435761u * " << name << ");"; + } + } + else + { + _M << name << ";"; + } + } + else + { + _M << "[self->" << name << " hash];"; + } + } + _M << nl << "return h_;"; + _M << eb; +} + +void +Slice::Gen::TypesVisitor::writeMemberEquals(const DataMemberList& dataMembers, int baseType) const +{ + if(!dataMembers.empty()) + { + ContainerPtr container = (*dataMembers.begin())->container(); + ContainedPtr contained = ContainedPtr::dynamicCast(container); + string containerName = fixName(contained); + _M << nl << containerName << " *obj_ = (" << containerName << " *)o_;"; + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + string name = fixId((*q)->name(), baseType); + + if(isValueType(type)) + { + _M << nl << "if(" << name << " != obj_->" << name << ")"; + _M << sb; + _M << nl << "return NO;"; + _M << eb; + } + else + { + _M << nl << "if(!" << name << ")"; + _M << sb; + _M << nl << "if(obj_->" << name << ")"; + _M << sb; + _M << nl << "return NO;"; + _M << eb; + _M << eb; + _M << nl << "else"; + _M << sb; + _M << nl << "if(![self." << name << " "; + _M << (isString(type) ? "isEqualToString" : "isEqual"); + _M << ":obj_->" << name << "])"; + _M << sb; + _M << nl << "return NO;"; + _M << eb; + _M << eb; + } + } + } + _M << nl << "return YES;"; +} + +void +Slice::Gen::TypesVisitor::writeMemberDealloc(const DataMemberList& dataMembers, int baseType, bool slicedData) const +{ + bool once = false; + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + TypePtr type = (*q)->type(); + if(!isValueType(type)) + { + if(!once) + { + once = true; + _M << sp; + _M.zeroIndent(); + _M << nl << "#if defined(__clang__) && !__has_feature(objc_arc)"; + _M.restoreIndent(); + _M << nl << "-(void) dealloc"; + _M << sb; + } + + bool isValue = isValueType(type); + if(!isValue) + { + _M << nl << "[self->" << fixId((*q)->name(), baseType) << " release];"; + } + } + } + if(once) + { + if(slicedData) + { + _M << nl << "[(NSObject*)slicedData__ release];"; + } + _M << nl << "[super dealloc];"; + _M << eb; + _M.zeroIndent(); + _M << nl << "#endif"; + _M.restoreIndent(); + _H << nl << "// This class also overrides dealloc."; + } +} + +void +Slice::Gen::TypesVisitor::writeMemberMarshal(const DataMemberList& dataMembers, const DataMemberList& optionalMembers, + int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + if(!(*q)->optional()) + { + writeMarshalUnmarshalCode(_M, (*q)->type(), "self->" + fixId((*q)->name(), baseType), true, false); + } + } + for(DataMemberList::const_iterator q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + string name = fixId((*q)->name(), baseType); + string frmt = getOptionalFormat((*q)->type()); + _M << nl << "if(self->has_" << name << "__ && [os_ writeOptional:" << (*q)->tag() << " format:" << frmt << "])"; + _M << sb; + writeOptMemberMarshalUnmarshalCode(_M, (*q)->type(), "self->" + name, true); + _M << eb; + } +} + +void +Slice::Gen::TypesVisitor::writeMemberUnmarshal(const DataMemberList& dataMembers, const DataMemberList& optionalMembers, + int baseType) const +{ + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + if(!(*q)->optional()) + { + writeMarshalUnmarshalCode(_M, (*q)->type(), "self->" + fixId((*q)->name(), baseType), false, false); + } + } + for(DataMemberList::const_iterator q = optionalMembers.begin(); q != optionalMembers.end(); ++q) + { + string name = fixId((*q)->name(), baseType); + string frmt = getOptionalFormat((*q)->type()); + _M << nl << "if([is_ readOptional:" << (*q)->tag() << " format:" << frmt << "])"; + _M << sb; + _M << nl << "self->has_" << name << "__ = YES;"; + writeOptMemberMarshalUnmarshalCode(_M, (*q)->type(), "self->" + name, false); + _M << eb; + _M << nl << "else"; + _M << sb; + _M << nl << "self->has_" << name << "__ = NO;"; + _M << eb; + } +} + +Slice::Gen::ProxyVisitor::ProxyVisitor(Output& H, Output& M) + : ObjCVisitor(H, M) +{ +} + +bool +Slice::Gen::ProxyVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string name = fixName(p); + ClassList bases = p->bases(); + + _H << sp << nl << "@protocol " << name << "Prx <"; + if(bases.empty()) + { + _H << "ICEObjectPrx"; + } + else + { + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + _H << fixName(*q) + "Prx"; + if(++q != bases.end()) + { + _H << ", "; + } + } + } + _H << ">"; + + return true; +} + +void +Slice::Gen::ProxyVisitor::visitClassDefEnd(const ClassDefPtr&) +{ + _H << nl << "@end"; +} + +void +Slice::Gen::ProxyVisitor::visitOperation(const OperationPtr& p) +{ + string name = getName(p); + TypePtr returnType = p->returnType(); + string retString = outTypeToString(returnType, p->returnIsOptional()); + string params = getParams(p); + string marshalParams = getMarshalParams(p); + string unmarshalParams = getUnmarshalParams(p); + + // + // Write two versions of the operation--with and without a + // context parameter. + // + _H << nl << "-(" << retString << ") " << name << params << ";"; + + _H << nl << "-(" << retString << ") " << name << params; + if(!params.empty()) + { + _H << " context"; + } + _H << ":(ICEContext *)context;"; + + _H << nl << "-(id<ICEAsyncResult>) begin_" << p->name() << marshalParams << ";"; + _H << nl << "-(id<ICEAsyncResult>) begin_" << p->name() << marshalParams; + if(!marshalParams.empty()) + { + _H << " context"; + } + _H << ":(ICEContext *)context;"; + + _H << nl << "-(" << retString << ") end_" << p->name() << unmarshalParams; + if(!unmarshalParams.empty()) + { + _H << " result"; + } + _H << ":(id<ICEAsyncResult>)result;"; + + string responseCBSig = getResponseCBSig(p); + _H << nl << "-(id<ICEAsyncResult>) begin_" << p->name() << marshalParams; + if(!marshalParams.empty()) + { + _H << " response"; + } + _H << ":(" << responseCBSig << ")response_ exception:(void(^)(ICEException*))exception_;"; + + _H << nl << "-(id<ICEAsyncResult>) begin_" << p->name() << marshalParams; + if(!marshalParams.empty()) + { + _H << " context"; + } + _H << ":(ICEContext *)context"; + _H << " response:(" << responseCBSig << ")response_ exception:(void(^)(ICEException*))exception_;"; + + _H << nl << "-(id<ICEAsyncResult>) begin_" << p->name() << marshalParams; + if(!marshalParams.empty()) + { + _H << " response"; + } + _H << ":(" << responseCBSig << ")response_ exception:(void(^)(ICEException*))exception_ sent:(void(^)(BOOL))sent_;"; + + _H << nl << "-(id<ICEAsyncResult>) begin_" << p->name() << marshalParams; + if(!marshalParams.empty()) + { + _H << " context"; + } + _H << ":(ICEContext *)context"; + _H << " response:(" << responseCBSig << ")response_ exception:(void(^)(ICEException*))exception_ sent:(void(^)(BOOL))sent_;"; +} + +Slice::Gen::HelperVisitor::HelperVisitor(Output& H, Output& M) : + ObjCVisitor(H, M) +{ +} + +bool +Slice::Gen::HelperVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + // + // Proxy helper + // + { + string name = moduleName(findModule(p)) + p->name() + "PrxHelper"; + _H << sp << nl << "@interface " << name << " : ICEProxyHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(id) readRetained:(id<ICEInputStream>)stream"; + _M << sb; + _M << nl << "return [stream newProxy:[" << fixName(p) << "Prx class]];"; + _M << eb; + _M << nl << "@end"; + } + + // + // Class helper + // + { + string name = moduleName(findModule(p)) + p->name() + "Helper"; + if(p->isInterface()) + { + _H << sp << nl << "typedef ICEObjectHelper " << name << ";"; + } + else + { + _H << sp << nl << "@interface " << name << " : ICEObjectHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(void) readRetained:(ICEObject*ICE_STRONG_QUALIFIER*)obj stream:(id<ICEInputStream>)stream"; + _M << sb; + _M << nl << "[stream newObject:obj expectedType:[" << fixName(p) << " class]];"; + _M << eb; + _M << nl << "@end"; + } + } + return false; +} + +void +Slice::Gen::HelperVisitor::visitEnum(const EnumPtr& p) +{ + string name = moduleName(findModule(p)) + p->name() + "Helper"; + + _H << sp << nl << "@interface " << name << " : ICEEnumHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(ICEInt) getMinValue"; + _M << sb; + _M << nl << "return " << p->minValue() << ";"; + _M << eb; + _M << nl << "+(ICEInt) getMaxValue"; + _M << sb; + _M << nl << "return " << p->maxValue() << ";"; + _M << eb; + _M << nl << "@end"; +} + +void +Slice::Gen::HelperVisitor::visitSequence(const SequencePtr& p) +{ + string name = moduleName(findModule(p)) + p->name() + "Helper"; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(p->type()); + if(builtin) + { + _H << sp << nl << "typedef ICE" << getBuiltinName(builtin) << "SequenceHelper " << name << ";"; + return; + } + + EnumPtr en = EnumPtr::dynamicCast(p->type()); + if(en) + { + _H << sp << nl << "@interface " << name << " : ICEEnumSequenceHelper"; + _H << nl << "@end"; + + string typeS = typeToString(en); + int min = en->minValue(); + int max = en->maxValue(); + _M << sp << nl << "@implementation " << name; + _M << nl << "+(id) readRetained:(id<ICEInputStream>)stream"; + _M << sb; + _M << nl << "return [stream newEnumSeq:" << min << " max:" << max << "];"; + _M << eb; + _M << nl << "+(void) write:(id)obj stream:(id<ICEOutputStream>)stream"; + _M << sb; + _M << nl << "[stream writeEnumSeq:obj min:" << min << " max:" << max << "];"; + _M << eb; + _M << nl << "@end"; + return; + } + + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(p->type()); + if(cl) + { + _H << sp << nl << "@interface " << name << " : ICEObjectSequenceHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(id) readRetained:(id<ICEInputStream>)stream"; + _M << sb; + _M << nl << "return [stream newObjectSeq:[" << fixName(cl) << " class]];"; + _M << eb; + _M << nl << "@end"; + return; + } + + ProxyPtr proxy = ProxyPtr::dynamicCast(p->type()); + ContainedPtr contained = ContainedPtr::dynamicCast(p->type()); + _H << sp << nl << "@interface " << name << " : ICEArraySequenceHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(Class) getElementHelper"; + _M << sb; + if(proxy) + { + string name = moduleName(findModule(proxy->_class())) + proxy->_class()->name(); + _M << nl << "return [" << name << "PrxHelper class];"; + } + else + { + assert(contained); + _M << nl << "return [" << moduleName(findModule(contained)) + contained->name() + "Helper class];"; + } + _M << eb; + _M << nl << "+(Class) getOptionalHelper"; + _M << sb; + if(p->type()->isVariableLength()) + { + _M << nl << "return [ICEVarLengthOptionalHelper class];"; + } + else if(p->type()->minWireSize() == 1) + { + _M << nl << "return [ICEFixedSize1SequenceOptionalHelper class];"; + } + else + { + _M << nl << "return [ICEFixedSequenceOptionalHelper class];"; + } + _M << eb; + _M << nl << "@end"; +} + +void +Slice::Gen::HelperVisitor::visitDictionary(const DictionaryPtr& p) +{ + string name = moduleName(findModule(p)) + p->name() + "Helper"; + + TypePtr keyType = p->keyType(); + string keyS; + BuiltinPtr keyBuiltin = BuiltinPtr::dynamicCast(keyType); + if(keyBuiltin) + { + keyS = "ICE" + getBuiltinName(BuiltinPtr::dynamicCast(keyType)) + "Helper"; + } + else + { + ContainedPtr contained = ContainedPtr::dynamicCast(keyType); + keyS = moduleName(findModule(contained)) + contained->name() + "Helper"; + } + + string valueS; + TypePtr valueType = p->valueType(); + BuiltinPtr valueBuiltin = BuiltinPtr::dynamicCast(valueType); + ClassDeclPtr valueClass = ClassDeclPtr::dynamicCast(valueType); + if((valueBuiltin && valueBuiltin->kind() == Builtin::KindObject) || valueClass) + { + _H << sp << nl << "@interface " << name << " : ICEObjectDictionaryHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(id) readRetained:(id<ICEInputStream>)stream"; + _M << sb; + if(valueClass && !valueClass->isInterface()) + { + valueS = fixName(valueClass); + _M << nl << "return [stream newObjectDict:[" << keyS << " class] expectedType:[" << valueS << " class]];"; + } + else + { + _M << nl << "return [stream newObjectDict:[" << keyS << " class] expectedType:[ICEObject class]];"; + } + _M << eb; + _M << nl << "+(void) write:(id)obj stream:(id<ICEOutputStream>)stream"; + _M << sb; + _M << nl << "[stream writeObjectDict:obj helper:[" << keyS << " class]];"; + _M << eb; + _M << nl << "@end"; + return; + } + + ProxyPtr valueProxy = ProxyPtr::dynamicCast(valueType); + if(valueBuiltin) + { + valueS = "ICE" + getBuiltinName(BuiltinPtr::dynamicCast(valueType)) + "Helper"; + } + else if(valueProxy) + { + valueS = moduleName(findModule(valueProxy->_class())) + valueProxy->_class()->name() + "PrxHelper"; + } + else + { + ContainedPtr contained = ContainedPtr::dynamicCast(valueType); + valueS = moduleName(findModule(contained)) + contained->name() + "Helper"; + } + _H << sp << nl << "@interface " << name << " : ICEDictionaryHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name; + _M << nl << "+(ICEKeyValueTypeHelper) getKeyValueHelper"; + _M << sb; + _M << nl << "ICEKeyValueTypeHelper c;"; + _M << nl << "c.key = [" << keyS << " class];"; + _M << nl << "c.value = [" << valueS << " class];"; + _M << nl << "return c;"; + _M << eb; + _M << nl << "+(Class) getOptionalHelper"; + _M << sb; + if(keyType->isVariableLength() || valueType->isVariableLength()) + { + _M << nl << "return [ICEVarLengthOptionalHelper class];"; + } + else + { + _M << nl << "return [ICEFixedDictionaryOptionalHelper class];"; + } + _M << eb; + _M << nl << "@end"; +} + + +bool +Slice::Gen::HelperVisitor::visitStructStart(const StructPtr& p) +{ + string name = fixName(p); + + _H << sp << nl << "@interface " << name << "Helper : ICEStructHelper"; + _H << nl << "@end"; + + _M << sp << nl << "@implementation " << name << "Helper"; + + _M << nl << "+(Class) getType"; + _M << sb; + _M << nl << "return [" << name << " class];"; + _M << eb; + _M << nl << "+(Class) getOptionalHelper"; + _M << sb; + if(p->isVariableLength()) + { + _M << nl << "return [ICEVarLengthOptionalHelper class];"; + } + else + { + _M << nl << "return [ICEFixedLengthOptionalHelper class];"; + } + _M << eb; + + _M << nl << "+(ICEInt) minWireSize"; + _M << sb; + _M << nl << "return " << p->minWireSize() << ";"; + _M << eb; + + _M << nl << "@end"; + return false; +} + +Slice::Gen::DelegateMVisitor::DelegateMVisitor(Output& H, Output& M) + : ObjCVisitor(H, M) +{ +} + +bool +Slice::Gen::DelegateMVisitor::visitModuleStart(const ModulePtr& p) +{ + return true; +} + +void +Slice::Gen::DelegateMVisitor::visitModuleEnd(const ModulePtr&) +{ +} + +bool +Slice::Gen::DelegateMVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string name = fixName(p); + ClassList bases = p->bases(); + OperationList ops = p->allOperations(); + OperationList::const_iterator r; + + _H << sp << nl << "@interface " << name << "Prx : ICEObjectPrx <" << name << "Prx>"; + _H << nl << "+(NSString *) ice_staticId;"; + + _M << sp << nl << "@implementation " << name << "Prx"; + for(r = ops.begin(); r != ops.end(); ++r) + { + string opName = getName(*r); + TypePtr returnType = (*r)->returnType(); + string retString = outTypeToString(returnType, (*r)->returnIsOptional()); + string params = getParams(*r); + string args = getArgs(*r); + + ParamDeclList inParams; + ParamDeclList outParams; + ParamDeclList paramList = (*r)->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + else + { + inParams.push_back(*pli); + } + } + + ContainerPtr container = (*r)->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string className = fixName(cl); + + // + // Write context-less operation that forwards to the version with a context. + // + _M << sp << nl << "-(" << retString << ") " << opName << params; + _M << sb; + _M << nl; + if(returnType) + { + _M << "return "; + } + _M << "[self " << opName << args << (args.empty() ? ":nil" : " context:nil") << "];"; + _M << eb; + + // + // Write version with context. + // + _M << sp << nl << "-(" << retString << ") " << opName << params; + if(!params.empty()) + { + _M << " context"; + } + _M << ":(ICEContext *)ctx_"; + _M << sb; + if(returnType) + { + _M << nl << "__block " << retString << " ret_"; + if(!isValueType(returnType)) + { + _M << " = nil;"; + } + else + { + _M << ";"; + } + } + + string marshal; + string marshalArgs = getMarshalArgs(*r); + string marshalParams = getMarshalParams(*r); + if(!inParams.empty()) + { + _M << nl << "ICEMarshalCB marshal_ = ^(id<ICEOutputStream> os_) "; + _M << "{ [" << className << "Prx " << (*r)->name() << "_marshal___" << marshalArgs; + _M << (marshalArgs.empty() ? ":os_" : " os:os_") << "]; };"; + marshal = "marshal_"; + } + else + { + marshal = "nil"; + } + + string unmarshal; + string unmarshalArgs = getUnmarshalArgs(*r); + string unmarshalParams = getUnmarshalParams(*r); + if((*r)->returnsData()) + { + _M << nl << "ICEUnmarshalCB unmarshal_ = ^(id<ICEInputStream> is_, BOOL ok_) "; + if(returnType) + { + _M << "{ ret_ = "; + } + else + { + _M << "{ "; + } + _M << "[" << className << "Prx " << (*r)->name() << "_unmarshal___" << unmarshalArgs; + _M << (unmarshalArgs.empty() ? ":is_" : " is:is_") << " ok:ok_]; };"; + unmarshal = "unmarshal_"; + } + else + { + unmarshal = "nil"; + } + + _M << nl << "[self invoke__:@\"" << (*r)->name() << "\" mode:" << sliceModeToIceMode((*r)->sendMode()) + << " format:" << opFormatTypeToString(*r) << " marshal:" << marshal + << " unmarshal:" << unmarshal << " context:ctx_];"; + if(returnType) + { + _M << nl << "return ret_;"; + } + _M << eb; + + // + // Write begin_ context-less operation that forwards to the version with a context. + // + _M << sp << nl << "-(id<ICEAsyncResult>) begin_" << (*r)->name() << marshalParams; + _M << sb; + _M << nl << "return [self begin_" << (*r)->name() << marshalArgs; + _M << (marshalArgs.empty() ? "" : " context") << ":nil];"; + _M << eb; + + // + // Write begin_ version with context. + // + _M << sp << nl << "-(id<ICEAsyncResult>) begin_" << (*r)->name() << marshalParams; + _M << (marshalParams.empty() ? "" : " context") << ":(ICEContext *)ctx_"; + _M << sb; + if(!inParams.empty()) + { + _M << nl << "ICEMarshalCB marshal_ = ^(id<ICEOutputStream> os_) "; + _M << "{ [" << className << "Prx " << (*r)->name() << "_marshal___" << marshalArgs; + _M << (marshalArgs.empty() ? "" : " os") << ":os_]; };"; + } + _M << nl << "return [self begin_invoke__:@\"" << (*r)->name() << "\" mode:" + << sliceModeToIceMode((*r)->sendMode()) << " format:" << opFormatTypeToString(*r) + << " marshal:" << marshal + << " returnsData:" << ((*r)->returnsData() ? "YES" : "NO") + << " context:ctx_];"; + _M << eb; + + // + // Write end_ operation + // + _M << sp << nl << "-(" << retString << ") end_" << (*r)->name() << unmarshalParams; + if(!unmarshalParams.empty()) + { + _M << " result"; + } + _M << ":(id<ICEAsyncResult>)result_"; + _M << sb; + if(returnType) + { + _M << nl << "__block " << retString << " ret_"; + if(!isValueType(returnType)) + { + _M << " = nil;"; + } + else + { + _M << ";"; + } + } + if((*r)->returnsData()) + { + _M << nl << "ICEUnmarshalCB unmarshal_ = ^(id<ICEInputStream> is_, BOOL ok_) "; + if(returnType) + { + _M << "{ ret_ = "; + } + else + { + _M << "{ "; + } + _M << "[" << className << "Prx " << (*r)->name() << "_unmarshal___" << unmarshalArgs; + _M << (unmarshalArgs.empty() ? ":is_" : " is:is_") << " ok:ok_]; };"; + } + _M << nl << "[self end_invoke__:@\"" << (*r)->name() << "\" unmarshal:" << unmarshal << " result:result_];"; + if(returnType) + { + _M << nl << "return ret_;"; + } + _M << eb; + + // + // Write begin_ operations with callbacks + // + string responseCBSig = getResponseCBSig(*r); + + _M << sp << nl << "-(id<ICEAsyncResult>) begin_" << (*r)->name() << marshalParams; + _M << (marshalParams.empty() ? "" : " response") << ":(" << responseCBSig << ")response_"; + _M << " exception:(void(^)(ICEException*))exception_"; + _M << sb; + _M << nl << "return [self begin_" << (*r)->name() << marshalArgs; + _M << (marshalArgs.empty() ? "" : " context") << ":nil response:response_ exception:exception_ sent:nil];"; + _M << eb; + + _M << sp << nl << "-(id<ICEAsyncResult>) begin_" << (*r)->name() << marshalParams; + _M << (marshalParams.empty() ? "" : " response") << ":(" << responseCBSig << ")response_"; + _M << " exception:(void(^)(ICEException*))exception_ sent:(void(^)(BOOL))sent_"; + _M << sb; + _M << nl << "return [self begin_" << (*r)->name() << marshalArgs; + _M << (marshalArgs.empty() ? "" : " context") << ":nil response:response_ exception:exception_ sent:sent_];"; + _M << eb; + + _M << sp << nl << "-(id<ICEAsyncResult>) begin_" << (*r)->name() << marshalParams; + _M << (marshalParams.empty() ? "" : " context") << ":(ICEContext*)ctx_"; + _M << " response:(" << responseCBSig << ")response_ exception:(void(^)(ICEException*))exception_ "; + _M << sb; + _M << nl << "return [self begin_" << (*r)->name() << marshalArgs; + _M << (marshalArgs.empty() ? "" : " context") << ":ctx_ response:response_ exception:exception_ sent:nil];"; + _M << eb; + + _M << sp << nl << "-(id<ICEAsyncResult>) begin_" << (*r)->name() << marshalParams; + _M << (marshalParams.empty() ? "" : " context") << ":(ICEContext*)ctx_"; + _M << " response:(" << responseCBSig << ")response_ exception:(void(^)(ICEException*))exception_ "; + _M << " sent:(void(^)(BOOL))sent_"; + _M << sb; + if(!inParams.empty()) + { + _M << nl << "ICEMarshalCB marshal_ = ^(id<ICEOutputStream> os_) "; + _M << "{ [" << className << "Prx " << (*r)->name() << "_marshal___" << marshalArgs; + _M << (marshalArgs.empty() ? "" : " os") << ":os_]; };"; + } + if((*r)->returnsData()) + { + _M << nl << "void(^completed_)(id<ICEInputStream>, BOOL) = ^(id<ICEInputStream> is_, BOOL ok_)"; + _M << sb; + string responseCallArgs; + string unmarshalCallArgs; + if(!outParams.empty() || returnType) + { + if(returnType) + { + responseCallArgs += "ret_"; + } + + for(ParamDeclList::const_iterator op = outParams.begin(); op != outParams.end(); ++op) + { + string name = fixId((*op)->name()); + _M << nl << outTypeToString((*op)->type(), (*op)->optional(), true) << " " << name; + if(!isValueType((*op)->type())) + { + _M << " = nil"; + } + _M << ";"; + + if(!unmarshalCallArgs.empty()) + { + unmarshalCallArgs += " " + name; + } + unmarshalCallArgs += ":&" + name; + + if(!responseCallArgs.empty()) + { + responseCallArgs += ", "; + } + responseCallArgs += name; + } + if(returnType) + { + _M << nl << outTypeToString(returnType, (*r)->returnIsOptional(), true) << " ret_"; + if(!isValueType(returnType)) + { + _M << " = nil"; + } + _M << ";"; + } + } + _M << nl << "@try"; + _M << sb; + _M << nl; + if(returnType) + { + _M << "ret_ = "; + } + _M << "[" << className << "Prx " << (*r)->name() << "_unmarshal___" << unmarshalCallArgs; + _M << (unmarshalCallArgs.empty() ? ":is_" : " is:is_") << " ok:ok_];"; + _M << eb; + _M << nl << "@catch(ICEException* ex)"; + _M << sb; + _M << nl << "if(exception_)"; + _M << sb; + _M << nl << "exception_(ex);"; + _M << eb; + _M << nl << "return;"; + _M << eb; + _M << nl << "if(response_)"; + _M << sb; + _M << nl << "response_(" << responseCallArgs << ");"; + _M << eb; + _M << eb << ";"; + if(returnType || !outParams.empty()) + { + _M << nl << "return [self begin_invoke__:@\"" << (*r)->name() << "\" mode:" + << sliceModeToIceMode((*r)->sendMode()) << " format:" << opFormatTypeToString(*r) + << " marshal:" << marshal + << " completed:completed_ response:(response_ != nil) exception:exception_ sent:sent_ context:ctx_];"; + } + else + { + _M << nl << "return [self begin_invoke__:@\"" << (*r)->name() << "\" mode:" + << sliceModeToIceMode((*r)->sendMode()) << " format:" << opFormatTypeToString(*r) + << " marshal:" << marshal << " completed:completed_ response:YES exception:exception_ sent:sent_ context:ctx_];"; + } + } + else + { + _M << nl << "return [self begin_invoke__:@\"" << (*r)->name() << "\" mode:" + << sliceModeToIceMode((*r)->sendMode()) << " format:" << opFormatTypeToString(*r) + << " marshal:" << marshal << " response:response_ exception:exception_ sent:sent_ context:ctx_];"; + } + _M << eb; + } + + _M << sp << nl << "+(NSString *) ice_staticId"; + _M << sb; + _M << nl << "return @\"" << p->scoped() << "\";"; + _M << eb; + + return true; +} + +void +Slice::Gen::DelegateMVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + _H << nl << "@end"; + _M << nl << "@end"; +} + +void +Slice::Gen::DelegateMVisitor::visitOperation(const OperationPtr& p) +{ + TypePtr returnType = p->returnType(); + string retString = outTypeToString(returnType, p->returnIsOptional()); + string params = getParams(p); + string args = getParams(p); + string marshalParams = getMarshalParams(p); + string unmarshalParams = getUnmarshalParams(p); + + ParamDeclList inParams; + ParamDeclList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator pli = paramList.begin(); pli != paramList.end(); ++pli) + { + if((*pli)->isOutParam()) + { + outParams.push_back(*pli); + } + else + { + inParams.push_back(*pli); + } + } + + // + // Write class method to invoke each operation. + // + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string className = fixName(cl); + if(!inParams.empty()) + { + _H << nl << "+(void) " << p->name() << "_marshal___" << marshalParams; + if(!marshalParams.empty()) + { + _H << " os"; + } + _H << ":(id<ICEOutputStream>)os_;"; + + _M << sp << nl << "+(void) " << p->name() << "_marshal___" << marshalParams; + if(!marshalParams.empty()) + { + _M << " os"; + } + _M << ":(id<ICEOutputStream>)os_"; + _M << sb; + writeMarshalUnmarshalParams(inParams, 0, true); + if(p->sendsClasses(false)) + { + _M << nl << "[os_ writePendingObjects];"; + } + _M << eb; + } + + if(p->returnsData()) + { + _H << nl << "+(" << retString << ")" << p->name() << "_unmarshal___" << unmarshalParams; + if(!unmarshalParams.empty()) + { + _H << " is"; + } + _H << ":(id<ICEInputStream>)is_ ok:(BOOL)ok_;"; + + _M << nl << "+(" << retString << ")" << p->name() << "_unmarshal___" << unmarshalParams; + if(!unmarshalParams.empty()) + { + _M << " is"; + } + _M << ":(id<ICEInputStream>)is_ ok:(BOOL)ok_"; + _M << sb; + if(returnType) + { + _M << nl << outTypeToString(returnType, p->returnIsOptional(), true) << " ret_"; + if(!isValueType(returnType)) + { + _M << " = nil;"; + } + else + { + _M << ";"; + } + } + if(p->returnsData()) + { + for(ParamDeclList::const_iterator op = outParams.begin(); op != outParams.end(); ++op) + { + if(!isValueType((*op)->type())) + { + _M << nl << "*" << fixId((*op)->name()) << " = nil;"; + } + } + } + _M << nl << "if(!ok_)"; + _M << sb; + _M << nl << "@try"; + _M << sb; + _M << nl << "[is_ startEncapsulation];"; + _M << nl << "[is_ throwException];"; + _M << eb; + // + // Arrange exceptions into most-derived to least-derived order. If we don't + // do this, a base exception handler can appear before a derived exception + // handler, causing compiler warnings and resulting in the base exception + // being marshaled instead of the derived exception. + // + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); + throws.sort(Slice::DerivedToBaseCompare()); + + for(ExceptionList::const_iterator e = throws.begin(); e != throws.end(); ++e) + { + _M << nl << "@catch(" << fixName(*e) << " *ex_)"; + _M << sb; + _M << nl << "[is_ endEncapsulation];"; + _M << nl << "@throw;"; + _M << eb; + } + _M << nl << "@catch(ICEUserException *ex_)"; + _M << sb; + _M << nl << "[is_ endEncapsulation];"; + _M << nl << "@throw [ICEUnknownUserException unknownUserException:__FILE__ line:__LINE__ " + << "unknown:[ex_ ice_name]];"; + _M << eb; + _M << eb; + + if(returnType || !outParams.empty()) + { + _M << nl << "else"; + _M << sb; + _M << nl << "[is_ startEncapsulation];"; + writeMarshalUnmarshalParams(outParams, p, false, true); + if(p->returnsClasses(false)) + { + _M << nl << "[is_ readPendingObjects];"; + } + _M << nl << "[is_ endEncapsulation];"; + _M << eb; + } + + if(returnType) + { + _M << nl << "return ret_;"; + } + _M << eb; + } +} + diff --git a/cpp/src/slice2objc/Gen.h b/cpp/src/slice2objc/Gen.h new file mode 100644 index 00000000000..2126057137e --- /dev/null +++ b/cpp/src/slice2objc/Gen.h @@ -0,0 +1,186 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#ifndef GEN_H +#define GEN_H + +#include <Slice/ObjCUtil.h> + +namespace Slice +{ + + +class ObjCVisitor : public ObjCGenerator, public ParserVisitor +{ +public: + + ObjCVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + virtual ~ObjCVisitor(); + +protected: + + virtual void writeDispatchAndMarshalling(const ClassDefPtr&); + virtual void writeMarshalUnmarshalParams(const ParamDeclList&, const OperationPtr&, bool, bool = false); + virtual std::string getName(const OperationPtr&) const; + virtual std::string getSelector(const OperationPtr&) const; + virtual std::string getParams(const OperationPtr&) const; + virtual std::string getMarshalParams(const OperationPtr&) const; + virtual std::string getUnmarshalParams(const OperationPtr&) const; + virtual std::string getServerParams(const OperationPtr&) const; + virtual std::string getResponseCBSig(const OperationPtr&) const; + virtual std::string getArgs(const OperationPtr&) const; + virtual std::string getMarshalArgs(const OperationPtr&) const; + virtual std::string getUnmarshalArgs(const OperationPtr&) const; + virtual std::string getServerArgs(const OperationPtr&) const; + + ::IceUtilInternal::Output& _H; + ::IceUtilInternal::Output& _M; +}; + +class Gen : private ::IceUtil::noncopyable +{ +public: + + Gen(const std::string&, + const std::string&, + const std::string&, + const std::vector<std::string>&, + const std::string&); + ~Gen(); + + bool operator!() const; // Returns true if there was a constructor error + + void generate(const UnitPtr&); + void closeOutput(); + +private: + + IceUtilInternal::Output _H; + IceUtilInternal::Output _M; + + std::string _base; + std::string _include; + std::vector<std::string> _includePaths; + + void printHeader(::IceUtilInternal::Output&); + + class UnitVisitor : public ObjCVisitor + { + public: + + UnitVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual bool visitModuleStart(const ModulePtr&); + virtual void visitUnitEnd(const UnitPtr&); + + private: + + std::vector<Slice::ObjCGenerator::ModulePrefix> _prefixes; + }; + + class ObjectDeclVisitor : public ObjCVisitor + { + public: + + ObjectDeclVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual void visitClassDecl(const ClassDeclPtr&); + }; + + class ProxyDeclVisitor : public ObjCVisitor + { + public: + + ProxyDeclVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual void visitClassDecl(const ClassDeclPtr&); + }; + + class TypesVisitor : public ObjCVisitor + { + public: + + TypesVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual bool visitModuleStart(const ModulePtr&); + virtual void visitModuleEnd(const ModulePtr&); + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitOperation(const OperationPtr&); + virtual void visitClassDefEnd(const ClassDefPtr&); + virtual bool visitExceptionStart(const ExceptionPtr&); + virtual void visitExceptionEnd(const ExceptionPtr&); + virtual bool visitStructStart(const StructPtr&); + virtual void visitStructEnd(const StructPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + virtual void visitEnum(const EnumPtr&); + virtual void visitConst(const ConstPtr&); + + private: + + enum Escape { NoEscape, WithEscape }; + enum ContainerType { LocalException, Other }; + + void writeConstantValue(IceUtilInternal::Output&, const TypePtr&, const std::string&) const; + void writeMembers(const DataMemberList&, int) const; + void writeMemberSignature(const DataMemberList&, int, ContainerType) const; + void writeMemberCall(const DataMemberList&, int, ContainerType, Escape) const; + void writeMemberDefaultValueInit(const DataMemberList&, int) const; + void writeMemberInit(const DataMemberList&, int) const; + void writeProperties(const DataMemberList&, int) const; + void writeSynthesize(const DataMemberList&, int) const; + void writeOptionalDataMemberSelectors(const DataMemberList&, int) const; + void writeMemberHashCode(const DataMemberList&, int) const; + void writeMemberEquals(const DataMemberList&, int) const; + void writeMemberDealloc(const DataMemberList&, int, bool slicedData = false) const; + void writeMemberMarshal(const DataMemberList&, const DataMemberList&, int) const; + void writeMemberUnmarshal(const DataMemberList&, const DataMemberList&, int) const; + }; + + class ProxyVisitor : public ObjCVisitor + { + public: + + ProxyVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitClassDefEnd(const ClassDefPtr&); + virtual void visitOperation(const OperationPtr&); + }; + + class HelperVisitor : public ObjCVisitor + { + public: + + HelperVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitEnum(const EnumPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + virtual bool visitStructStart(const StructPtr&); + }; + + class DelegateMVisitor : public ObjCVisitor + { + public: + + DelegateMVisitor(::IceUtilInternal::Output&, ::IceUtilInternal::Output&); + + virtual bool visitModuleStart(const ModulePtr&); + virtual void visitModuleEnd(const ModulePtr&); + virtual bool visitClassDefStart(const ClassDefPtr&); + virtual void visitClassDefEnd(const ClassDefPtr&); + virtual void visitOperation(const OperationPtr&); + }; +}; + +} + +#endif diff --git a/cpp/src/slice2objc/Main.cpp b/cpp/src/slice2objc/Main.cpp new file mode 100644 index 00000000000..529c54134b2 --- /dev/null +++ b/cpp/src/slice2objc/Main.cpp @@ -0,0 +1,290 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/Options.h> +#include <Slice/Preprocessor.h> +#include <Slice/FileTracker.h> +#include <IceUtil/CtrlCHandler.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/MutexPtrLock.h> +#include <Slice/Util.h> +#include <Gen.h> + +using namespace std; +using namespace Slice; + +namespace +{ + +IceUtil::Mutex* globalMutex = 0; +bool interrupted = false; + +class Init +{ +public: + + Init() + { + globalMutex = new IceUtil::Mutex; + } + + ~Init() + { + delete globalMutex; + globalMutex = 0; + } +}; + +Init init; + +} + +void +interruptedCallback(int signal) +{ + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); + interrupted = true; +} + +void +usage(const char* n) +{ + cerr << "Usage: " << n << " [options] slice-files...\n"; + cerr << + "Options:\n" + "-h, --help Show this message.\n" + "-v, --version Display the Ice version.\n" + "-DNAME Define NAME as 1.\n" + "-DNAME=DEF Define NAME as DEF.\n" + "-UNAME Remove any definition for NAME.\n" + "-IDIR Put DIR in the include file search path.\n" + "-E Print preprocessor output on stdout.\n" + "--include-dir DIR Use DIR as the header include directory in source files.\n" + "--output-dir DIR Create files in the directory DIR.\n" + "--depend Generate Makefile dependencies.\n" + "--depend-xml Generate dependencies in XML format.\n" + "-d, --debug Print debug messages.\n" + "--ice Permit `Ice' prefix (for building Ice source code only)\n" + "--underscore Permit underscores in Slice identifiers.\n" + ; + // Note: --case-sensitive is intentionally not shown here! +} + +int +main(int argc, char* argv[]) +{ + IceUtilInternal::Options opts; + opts.addOpt("h", "help"); + opts.addOpt("v", "version"); + opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("E"); + opts.addOpt("", "include-dir", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "depend"); + opts.addOpt("", "depend-xml"); + opts.addOpt("d", "debug"); + opts.addOpt("", "ice"); + opts.addOpt("", "underscore"); + opts.addOpt("", "case-sensitive"); + + vector<string> args; + try + { + args = opts.parse(argc, (const char**)argv); + } + catch(const IceUtilInternal::BadOptException& e) + { + cerr << argv[0] << ": " << e.reason << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(opts.isSet("help")) + { + usage(argv[0]); + return EXIT_SUCCESS; + } + + if(opts.isSet("version")) + { + cout << ICE_STRING_VERSION << endl; + return EXIT_SUCCESS; + } + + vector<string> cppArgs; + vector<string> optargs = opts.argVec("D"); + vector<string>::const_iterator i; + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-D" + *i); + } + + optargs = opts.argVec("U"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-U" + *i); + } + + vector<string> includePaths = opts.argVec("I"); + for(i = includePaths.begin(); i != includePaths.end(); ++i) + { + cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i)); + } + + bool preprocess = opts.isSet("E"); + + string include = opts.optArg("include-dir"); + + string output = opts.optArg("output-dir"); + + bool depend = opts.isSet("depend"); + bool dependxml = opts.isSet("depend-xml"); + + bool debug = opts.isSet("debug"); + + bool ice = opts.isSet("ice"); + + bool underscore = opts.isSet("underscore"); + + if(args.empty()) + { + getErrorStream() << argv[0] << ": no input file" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + int status = EXIT_SUCCESS; + + if(dependxml) + { + cout << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dependencies>" << endl; + } + + IceUtil::CtrlCHandler ctrlCHandler; + ctrlCHandler.setCallback(interruptedCallback); + + for(i = args.begin(); i != args.end(); ++i) + { + if(depend || dependxml) + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); + FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2OBJC__"); + + if(cppHandle == 0) + { + return EXIT_FAILURE; + } + + UnitPtr u = Unit::createUnit(false, false, ice, underscore); + int parseStatus = u->parse(*i, cppHandle, debug); + u->destroy(); + + if(parseStatus == EXIT_FAILURE) + { + return EXIT_FAILURE; + } + + if(!icecpp->printMakefileDependencies(depend ? Preprocessor::ObjC : Preprocessor::JavaXML, + includePaths, "-D__SLICE2OBJC__")) + { + return EXIT_FAILURE; + } + + if(!icecpp->close()) + { + return EXIT_FAILURE; + } + } + else + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs); + FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2OBJC__"); + + if(cppHandle == 0) + { + return EXIT_FAILURE; + } + + if(preprocess) + { + char buf[4096]; + while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != NULL) + { + if(fputs(buf, stdout) == EOF) + { + return EXIT_FAILURE; + } + } + if(!icecpp->close()) + { + return EXIT_FAILURE; + } + } + else + { + UnitPtr u = Unit::createUnit(false, false, ice, underscore); + int parseStatus = u->parse(*i, cppHandle, debug); + + if(!icecpp->close()) + { + u->destroy(); + return EXIT_FAILURE; + } + + if(parseStatus == EXIT_FAILURE) + { + status = EXIT_FAILURE; + } + else + { + try + { + Gen gen(argv[0], icecpp->getBaseName(), include, includePaths, output); + if(!gen) + { + u->destroy(); + return EXIT_FAILURE; + } + gen.generate(u); + } + catch(const Slice::FileException& ex) + { + // If a file could not be created, then + // cleanup any created files. + FileTracker::instance()->cleanup(); + u->destroy(); + getErrorStream() << argv[0] << ": error: " << ex.reason() << endl; + return EXIT_FAILURE; + } + } + + u->destroy(); + } + } + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); + + if(interrupted) + { + FileTracker::instance()->cleanup(); + return EXIT_FAILURE; + } + } + } + + if(dependxml) + { + cout << "</dependencies>\n"; + } + + return status; +} diff --git a/cpp/src/slice2objc/Makefile b/cpp/src/slice2objc/Makefile new file mode 100644 index 00000000000..bd540f310b2 --- /dev/null +++ b/cpp/src/slice2objc/Makefile @@ -0,0 +1,31 @@ +# ********************************************************************** +# +# Copyright (c) 2003-2014 ZeroC, Inc. All rights reserved. +# +# This copy of Ice is licensed to you under the terms described in the +# ICE_LICENSE file included in this distribution. +# +# ********************************************************************** + +top_srcdir = ../.. + +NAME = $(bindir)/slice2objc$(EXE_EXT) + +TARGETS = $(NAME) + +OBJS = Gen.o \ + Main.o + +RPATH_DIR = $(LOADER_PATH)/../$(libsubdir) + +include $(top_srcdir)/config/Make.rules + +CPPFLAGS := -I. $(CPPFLAGS) + +$(NAME): $(OBJS) + rm -f $@ + $(CXX) $(LDFLAGS) $(LDEXEFLAGS) -o $@ $(OBJS) $(SLICE_LIBS) $(MCPP_RPATH_LINK) + +install:: all + $(call installprogram,$(NAME),$(DESTDIR)$(install_bindir)) + $(call installdata,$(top_srcdir)/../man/man1/slice2objc.1,$(DESTDIR)$(install_mandir)) |