summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorBenoit Foucher <benoit@zeroc.com>2015-01-07 15:11:14 +0100
committerBenoit Foucher <benoit@zeroc.com>2015-01-07 15:11:14 +0100
commitc126ec03755c9cea578c3b6584ed64c7ba065232 (patch)
tree453ad5f807fdca1deaa8b16ee62853b414ba1e58 /cpp/src
parentICE-6082 added sndBufSize and rcvBufSize to UDPEndpointInfo (diff)
downloadice-c126ec03755c9cea578c3b6584ed64c7ba065232.tar.bz2
ice-c126ec03755c9cea578c3b6584ed64c7ba065232.tar.xz
ice-c126ec03755c9cea578c3b6584ed64c7ba065232.zip
Added Objective-C mapping
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/Ice/Makefile2
-rw-r--r--cpp/src/Makefile14
-rw-r--r--cpp/src/Slice/Makefile1
-rw-r--r--cpp/src/Slice/ObjCUtil.cpp1204
-rw-r--r--cpp/src/Slice/Preprocessor.cpp10
-rw-r--r--cpp/src/slice2objc/Gen.cpp3139
-rw-r--r--cpp/src/slice2objc/Gen.h186
-rw-r--r--cpp/src/slice2objc/Main.cpp290
-rw-r--r--cpp/src/slice2objc/Makefile31
9 files changed, 4872 insertions, 5 deletions
diff --git a/cpp/src/Ice/Makefile b/cpp/src/Ice/Makefile
index 7001e0d7a44..2f87cf2123c 100644
--- a/cpp/src/Ice/Makefile
+++ b/cpp/src/Ice/Makefile
@@ -54,7 +54,7 @@ SLICE_OBJS = BuiltinSequences.o \
SliceChecksumDict.o \
Version.o
-OBJS = Acceptor.o \
+OBJS = Acceptor.o \
ACM.o \
Application.o \
AsyncResult.o \
diff --git a/cpp/src/Makefile b/cpp/src/Makefile
index 89e7e3c423b..d9cd4c797fa 100644
--- a/cpp/src/Makefile
+++ b/cpp/src/Makefile
@@ -12,7 +12,7 @@ top_srcdir = ..
include $(top_srcdir)/config/Make.rules
ifneq ($(findstring MINGW,$(UNAME)),)
- SUBDIRS = IceUtil \
+ SUBDIRS = IceUtil \
Slice \
slice2cpp \
slice2rb \
@@ -20,7 +20,7 @@ ifneq ($(findstring MINGW,$(UNAME)),)
IceSSL \
IceDiscovery
else
- SUBDIRS = IceUtil \
+ SUBDIRS = IceUtil \
Slice \
slice2cpp \
slice2cs \
@@ -31,7 +31,13 @@ else
slice2py \
slice2rb \
slice2html \
- slice2js \
+ slice2js
+
+ifeq ($(UNAME),Darwin)
+ SUBDIRS := $(SUBDIRS) slice2objc
+endif
+
+ SUBDIRS := $(SUBDIRS) \
Ice \
IceXML \
IceSSL \
@@ -59,7 +65,7 @@ endif
Slice: IceUtil
-slice2cpp slice2cs slice2freeze slice2freezej slice2java slice2js slice2php slice2py slice2rb slice2html: Slice
+slice2cpp slice2cs slice2freeze slice2freezej slice2java slice2js slice2php slice2py slice2rb slice2html slice2objc: Slice
Ice: slice2cpp
diff --git a/cpp/src/Slice/Makefile b/cpp/src/Slice/Makefile
index d96009fad9e..4e816bc3ccb 100644
--- a/cpp/src/Slice/Makefile
+++ b/cpp/src/Slice/Makefile
@@ -22,6 +22,7 @@ OBJS = Checksum.o \
JavaUtil.o \
MD5.o \
MD5I.o \
+ ObjCUtil.o \
Parser.o \
PHPUtil.o \
Preprocessor.o \
diff --git a/cpp/src/Slice/ObjCUtil.cpp b/cpp/src/Slice/ObjCUtil.cpp
new file mode 100644
index 00000000000..cc3abd3b08b
--- /dev/null
+++ b/cpp/src/Slice/ObjCUtil.cpp
@@ -0,0 +1,1204 @@
+// **********************************************************************
+//
+// 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 <Slice/ObjCUtil.h>
+#include <Slice/Util.h>
+#include <IceUtil/Functional.h>
+#include <IceUtil/StringUtil.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef _WIN32
+#include <direct.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+using namespace IceUtilInternal;
+
+Slice::ObjCGenerator::ModuleMap Slice::ObjCGenerator::_modules;
+
+static string
+lookupKwd(const string& name, int baseType, bool mangleCasts = false)
+{
+ //
+ // All lists in this method *must* be kept in case-insensitive
+ // alphabetical order.
+ //
+ static string keywordList[] =
+ {
+ "auto", "BOOL", "break", "bycopy", "byref", "case", "char", "const", "continue",
+ "default", "do", "double", "else", "enum", "extern", "float", "for", "goto",
+ "id", "if", "IMP", "in", "inline", "inout", "int", "long", "nil", "NO", "oneway", "out",
+ "register", "return", "SEL", "self", "short", "signed", "sizeof", "static", "struct", "super", "switch",
+ "typedef", "union", "unsigned", "void", "volatile", "while", "YES"
+ };
+
+ static string nsObjectList[] =
+ {
+ "autorelease", "class", "classForCoder", "copy", "dealloc", "description", "hash", "init", "isa",
+ "isProxy", "mutableCopy", "release", "retain", "retainCount", "superclass", "zone"
+ };
+ static string nsExceptionList[] =
+ {
+ "callStackReturnAddresses", "name", "raise", "reason", "reserved", "userInfo",
+ };
+
+ bool found = binary_search(&keywordList[0],
+ &keywordList[sizeof(keywordList) / sizeof(*keywordList)],
+ name,
+ Slice::CICompare());
+ if(!found)
+ {
+ switch(baseType)
+ {
+ case BaseTypeNone:
+ break;
+
+ case BaseTypeException:
+ found = binary_search(&nsExceptionList[0],
+ &nsExceptionList[sizeof(nsExceptionList) / sizeof(*nsExceptionList)],
+ name,
+ Slice::CICompare());
+ if(found)
+ {
+ break;
+ }
+
+ case BaseTypeObject:
+ found = binary_search(&nsObjectList[0],
+ &nsObjectList[sizeof(nsObjectList) / sizeof(*nsObjectList)],
+ name,
+ Slice::CICompare());
+ break;
+ }
+ }
+ if(found || (mangleCasts && (name == "checkedCast" || name == "uncheckedCast")))
+ {
+ return name + "_";
+ }
+ return name;
+}
+
+bool
+Slice::ObjCGenerator::addModule(const ModulePtr& m, const string& name)
+{
+ string scoped = m->scoped();
+ ModuleMap::const_iterator i = _modules.find(scoped);
+ if(i != _modules.end())
+ {
+ if(i->second.name != name)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ ModulePrefix mp;
+ mp.m = m;
+ mp.name = name;
+ _modules[scoped] = mp;
+ }
+ return true;
+}
+
+Slice::ObjCGenerator::ModulePrefix
+Slice::ObjCGenerator::modulePrefix(const ModulePtr& m)
+{
+ return _modules[m->scoped()];
+}
+
+string
+Slice::ObjCGenerator::moduleName(const ModulePtr& m)
+{
+ return _modules[m->scoped()].name;
+}
+
+ModulePtr
+Slice::ObjCGenerator::findModule(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
+{
+ ModulePtr m = ModulePtr::dynamicCast(cont);
+ ContainerPtr container = cont->container();
+ while(container && !m)
+ {
+ ContainedPtr contained = ContainedPtr::dynamicCast(container);
+ container = contained->container();
+ m = ModulePtr::dynamicCast(contained);
+ }
+ assert(m);
+ return m;
+}
+
+//
+// If the passed name is a scoped name, return the identical scoped
+// name, but with all components that are Objective-C keywords
+// replaced by their prefixed version; otherwise, if the passed name
+// is not scoped, but an Objective-C keyword, return the prefixed
+// name; otherwise, check if the name is one of the method names of
+// baseTypes; if so, returned the prefixed name; otherwise, return the
+// name unchanged.
+//
+string
+Slice::ObjCGenerator::fixId(const string& name, int baseTypes, bool mangleCasts)
+{
+ if(name.empty())
+ {
+ return name;
+ }
+ return lookupKwd(name, baseTypes, mangleCasts);
+}
+
+string
+Slice::ObjCGenerator::fixId(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
+{
+ return fixId(cont->name(), baseTypes, mangleCasts);
+}
+
+string
+Slice::ObjCGenerator::fixName(const ContainedPtr& cont, int baseTypes, bool mangleCasts)
+{
+ return moduleName(findModule(cont, baseTypes, mangleCasts)) + cont->name();
+}
+
+string
+Slice::ObjCGenerator::typeToString(const TypePtr& type)
+{
+ if(!type)
+ {
+ return "void";
+ }
+
+ static const char* builtinTable[] =
+ {
+ "ICEByte",
+ "BOOL",
+ "ICEShort",
+ "ICEInt",
+ "ICELong",
+ "ICEFloat",
+ "ICEDouble",
+ "NSString",
+ "ICEObject",
+ "id<ICEObjectPrx>",
+ "id" // Dummy--we don't support Slice local Object
+ };
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return builtinTable[builtin->kind()];
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ string mName = moduleName(findModule(proxy->_class()));
+ return "id<" + mName + (proxy->_class()->name()) + "Prx>";
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return fixName(seq);
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ return fixName(d);
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl && cl->isInterface())
+ {
+ return "ICEObject";
+ }
+
+ ContainedPtr contained = ContainedPtr::dynamicCast(type);
+ if(contained)
+ {
+ return fixName(contained);
+ }
+
+ return "???";
+}
+
+string
+Slice::ObjCGenerator::inTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference)
+{
+ string s;
+ if(optional)
+ {
+ s = "id";
+ }
+ else
+ {
+ s = typeToString(type);
+ if(mapsToPointerType(type))
+ {
+ s += "*";
+ }
+ }
+ if(autoreleasing && !isValueType(type))
+ {
+ s += " ICE_AUTORELEASING_QUALIFIER";
+ }
+ if(reference)
+ {
+ s += "*";
+ }
+ return s;
+}
+
+string
+Slice::ObjCGenerator::outTypeToString(const TypePtr& type, bool optional, bool autoreleasing, bool reference)
+{
+ if(!type)
+ {
+ return "void";
+ }
+
+ string s;
+ if(optional)
+ {
+ s = "id";
+ }
+ else
+ {
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(isString(type))
+ {
+ s = "NSMutableString";
+ }
+ else if(seq)
+ {
+ string prefix = moduleName(findModule(seq));
+ s = prefix + "Mutable" + seq->name();
+ }
+ else if(d)
+ {
+ string prefix = moduleName(findModule(d));
+ s = prefix + "Mutable" + d->name();
+ }
+ else
+ {
+ s = typeToString(type);
+ }
+ if(mapsToPointerType(type))
+ {
+ s += "*";
+ }
+ }
+ if(autoreleasing && !isValueType(type))
+ {
+ s += " ICE_AUTORELEASING_QUALIFIER";
+ }
+ if(reference)
+ {
+ s += "*";
+ }
+ return s;
+}
+
+string
+Slice::ObjCGenerator::typeToObjCTypeString(const TypePtr& type)
+{
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ return moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "Prx";
+ }
+ else
+ {
+ return typeToString(type);
+ }
+}
+
+bool
+Slice::ObjCGenerator::isValueType(const TypePtr& type)
+{
+ if(!type)
+ {
+ return true;
+ }
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Builtin::KindString:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ return false;
+ break;
+ }
+ default:
+ {
+ return true;
+ break;
+ }
+ }
+ }
+ if(EnumPtr::dynamicCast(type))
+ {
+ return true;
+ }
+ return false;
+}
+
+bool
+Slice::ObjCGenerator::isString(const TypePtr& type)
+{
+ if(!type)
+ {
+ return false;
+ }
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ return builtin && builtin->kind() == Builtin::KindString;
+}
+bool
+Slice::ObjCGenerator::isClass(const TypePtr& type)
+{
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return builtin->kind() == Builtin::KindObject;
+ }
+ return ClassDeclPtr::dynamicCast(type);
+}
+
+bool
+Slice::ObjCGenerator::mapsToPointerType(const TypePtr& type)
+{
+ if(isValueType(type))
+ {
+ return false;
+ }
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return builtin->kind() != Builtin::KindObjectProxy;
+ }
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl && cl->isInterface())
+ {
+ return true;
+ }
+ return !ProxyPtr::dynamicCast(type);
+}
+
+string
+Slice::ObjCGenerator::getBuiltinName(const BuiltinPtr& builtin)
+{
+ switch(builtin->kind())
+ {
+ case Builtin::KindByte:
+ {
+ return "Byte";
+ }
+ case Builtin::KindBool:
+ {
+ return "Bool";
+ }
+ case Builtin::KindShort:
+ {
+ return "Short";
+ }
+ case Builtin::KindInt:
+ {
+ return "Int";
+ }
+ case Builtin::KindLong:
+ {
+ return "Long";
+ }
+ case Builtin::KindFloat:
+ {
+ return "Float";
+ }
+ case Builtin::KindDouble:
+ {
+ return "Double";
+ }
+ case Builtin::KindString:
+ {
+ return "String";
+ }
+ case Builtin::KindObject:
+ {
+ return "Object";
+ }
+ case Builtin::KindObjectProxy:
+ {
+ return "Proxy";
+ }
+ default:
+ {
+ assert(false);
+ }
+ }
+ return "NO__SUCH__TYPE";
+}
+
+string
+Slice::ObjCGenerator::getOptionalHelperGetter(const TypePtr& type)
+{
+ if(isValueType(type))
+ {
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ return "get" + getBuiltinName(builtin);
+ }
+ if(EnumPtr::dynamicCast(type))
+ {
+ return "getInt";
+ }
+ }
+ return "get";
+}
+
+//
+// Split a scoped name into its components and return the components as a list of (unscoped) identifiers.
+//
+StringList
+Slice::ObjCGenerator::splitScopedName(const string& scoped)
+{
+ assert(scoped[0] == ':');
+ StringList ids;
+ string::size_type next = 0;
+ string::size_type pos;
+ while((pos = scoped.find("::", next)) != string::npos)
+ {
+ pos += 2;
+ if(pos != scoped.size())
+ {
+ string::size_type endpos = scoped.find("::", pos);
+ if(endpos != string::npos)
+ {
+ ids.push_back(scoped.substr(pos, endpos - pos));
+ }
+ }
+ next = pos;
+ }
+ if(next != scoped.size())
+ {
+ ids.push_back(scoped.substr(next));
+ }
+ else
+ {
+ ids.push_back("");
+ }
+
+ return ids;
+}
+
+string
+Slice::ObjCGenerator::getOptionalFormat(const TypePtr& type)
+{
+ BuiltinPtr bp = BuiltinPtr::dynamicCast(type);
+ if(bp)
+ {
+ switch(bp->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindBool:
+ {
+ return "ICEOptionalFormatF1";
+ }
+ case Builtin::KindShort:
+ {
+ return "ICEOptionalFormatF2";
+ }
+ case Builtin::KindInt:
+ case Builtin::KindFloat:
+ {
+ return "ICEOptionalFormatF4";
+ }
+ case Builtin::KindLong:
+ case Builtin::KindDouble:
+ {
+ return "ICEOptionalFormatF8";
+ }
+ case Builtin::KindString:
+ {
+ return "ICEOptionalFormatVSize";
+ }
+ case Builtin::KindObject:
+ {
+ return "ICEOptionalFormatClass";
+ }
+ case Builtin::KindObjectProxy:
+ {
+ return "ICEOptionalFormatFSize";
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ }
+ }
+
+ if(EnumPtr::dynamicCast(type))
+ {
+ return "ICEOptionalFormatSize";
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return seq->type()->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ return (d->keyType()->isVariableLength() || d->valueType()->isVariableLength()) ?
+ "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ return st->isVariableLength() ? "ICEOptionalFormatFSize" : "ICEOptionalFormatVSize";
+ }
+
+ if(ProxyPtr::dynamicCast(type))
+ {
+ return "ICEOptionalFormatFSize";
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ assert(cl);
+ return "ICEOptionalFormatClass";
+}
+
+void
+Slice::ObjCGenerator::writeMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
+ bool marshal, bool autoreleased) const
+{
+ string stream = marshal ? "os_" : "is_";
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+
+ if(builtin)
+ {
+ string name;
+ if(builtin->kind() == Builtin::KindObject)
+ {
+ if(marshal)
+ {
+ out << nl << "[" << stream << " writeObject:" << param << "];";
+ }
+ else
+ {
+ if(autoreleased)
+ {
+ out << nl << "[" << stream << " readObject:&" << param << "];";
+ }
+ else
+ {
+ out << nl << "[" << stream << " newObject:&" << param << "];";
+ }
+ }
+ }
+ else if(builtin->kind() == Builtin::KindObjectProxy)
+ {
+ if(marshal)
+ {
+ out << nl << "[" << stream << " writeProxy:" << param << "];";
+ }
+ else
+ {
+ if(autoreleased)
+ {
+ out << nl << param << " = [" << stream << " readProxy:[ICEObjectPrx class]];";
+ }
+ else
+ {
+ out << nl << param << " = [" << stream << " newProxy:[ICEObjectPrx class]];";
+ }
+ }
+ }
+ else
+ {
+ if(marshal)
+ {
+ out << nl << "[" << stream << " write" << getBuiltinName(builtin) << ":" << param << "];";
+ }
+ else
+ {
+ if(autoreleased || isValueType(builtin))
+ {
+ out << nl << param << " = [" << stream << " read" << getBuiltinName(builtin) << "];";
+ }
+ else
+ {
+ out << nl << param << " = [" << stream << " new" << getBuiltinName(builtin) << "];";
+ }
+ }
+ }
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ if(marshal)
+ {
+ out << nl << "[" << stream << " writeProxy:(id<ICEObjectPrx>)" << param << "];";
+ }
+ else
+ {
+ string name = moduleName(findModule(prx->_class())) + prx->_class()->name() + "Prx";
+ out << nl << param << " = (id<" << name << ">)[" << stream;
+ if(autoreleased)
+ {
+ out << " readProxy:";
+ }
+ else
+ {
+ out << " newProxy:";
+ }
+ //
+ // We use objc_getClass to get the proxy class instead of [name class]. This is to avoid
+ // a warning if the proxy is forward declared.
+ //
+ if(prx->_class()->definition())
+ {
+ out << "[" << name << " class]];";
+ }
+ else
+ {
+ out << "objc_getClass(\"" << name << "\")];";
+ }
+ }
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ if(marshal)
+ {
+ // Cast avoids warning for forward-declared classes.
+ out << nl << "[" << stream << " writeObject:(ICEObject*)" << param << "];";
+ }
+ else
+ {
+ if(autoreleased)
+ {
+ out << nl << "[" << stream << " " << "readObject:(ICEObject**)&" << param;
+ }
+ else
+ {
+ out << nl << "[" << stream << " " << "newObject:(ICEObject**)&" << param;
+ }
+
+ if(cl->isInterface())
+ {
+ out << "];";
+ }
+ else
+ {
+ string name = moduleName(findModule(cl)) + cl->name();
+ if(cl->definition())
+ {
+ out << " expectedType:[" << name << " class]];";
+ }
+ else
+ {
+ out << " expectedType:objc_getClass(\"" << name << "\")];";
+ }
+ }
+ }
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ if(marshal)
+ {
+ out << nl << "[" << stream << " writeEnumerator:" << param << " min:" << en->minValue()
+ << " max:" << en->maxValue() << "];";
+ }
+ else
+ {
+ out << nl << param << " = " << "[" << stream << " readEnumerator:" << en->minValue()
+ << " max:" << en->maxValue() << "];";
+ }
+ return;
+ }
+
+ ContainedPtr c = ContainedPtr::dynamicCast(type);
+ assert(c);
+ string name = moduleName(findModule(c)) + c->name() + "Helper";
+ if(marshal)
+ {
+ out << nl << "[" + name << " write:" << param << " stream:" << stream << "];";
+ }
+ else
+ {
+ if(autoreleased)
+ {
+ out << nl << param << " = [" << name << " read:" << stream << "];";
+ }
+ else
+ {
+ out << nl << param << " = [" << name << " readRetained:" << stream << "];";
+ }
+ }
+}
+
+void
+Slice::ObjCGenerator::writeOptMemberMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
+ bool marshal) const
+{
+ string stream = marshal ? "os_" : "is_";
+ string optionalHelper;
+ string helper;
+
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ if(builtin->kind() == Builtin::KindObjectProxy)
+ {
+ optionalHelper = "ICEVarLengthOptionalHelper";
+ helper = "[ICEProxyHelper class]";
+ }
+ else
+ {
+ writeMarshalUnmarshalCode(out, type, param, marshal, false);
+ return;
+ }
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ writeMarshalUnmarshalCode(out, type, param, marshal, false);
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ writeMarshalUnmarshalCode(out, type, param, marshal, false);
+ return;
+ }
+
+ ProxyPtr prx = ProxyPtr::dynamicCast(type);
+ if(prx)
+ {
+ optionalHelper = "ICEVarLengthOptionalHelper";
+ helper = "objc_getClass(\"" + moduleName(findModule(prx->_class())) + prx->_class()->name() + "PrxHelper\")";
+ }
+
+ StructPtr st = StructPtr::dynamicCast(type);
+ if(st)
+ {
+ if(st->isVariableLength())
+ {
+ optionalHelper = "ICEVarLengthOptionalHelper";
+ }
+ else
+ {
+ optionalHelper = "ICEFixedLengthOptionalHelper";
+ }
+ helper = "[" + typeToString(st) + "Helper class]";
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ TypePtr element = seq->type();
+ if(element->isVariableLength())
+ {
+ optionalHelper = "ICEVarLengthOptionalHelper";
+ }
+ else if(element->minWireSize() == 1)
+ {
+ writeMarshalUnmarshalCode(out, type, param, marshal, false);
+ return;
+ }
+ else
+ {
+ optionalHelper = "ICEFixedSequenceOptionalHelper";
+ }
+ helper = "[" + moduleName(findModule(seq)) + seq->name() + "Helper class]";
+ }
+
+ DictionaryPtr d = DictionaryPtr::dynamicCast(type);
+ if(d)
+ {
+ if(d->keyType()->isVariableLength() || d->valueType()->isVariableLength())
+ {
+ optionalHelper = "ICEVarLengthOptionalHelper";
+ }
+ else
+ {
+ optionalHelper = "ICEFixedDictionaryOptionalHelper";
+ }
+ helper = "[" + moduleName(findModule(d)) + d->name() + "Helper class]";
+ }
+
+ out << nl;
+ if(marshal)
+ {
+ out << "[" << optionalHelper << " write:" << param << " stream:" << stream << " helper:" << helper << "];";
+ }
+ else
+ {
+ out << param << " = [" << optionalHelper << " readRetained:" << stream << " helper:" << helper << "];";
+ }
+
+}
+
+void
+Slice::ObjCGenerator::writeOptParamMarshalUnmarshalCode(Output &out, const TypePtr& type, const string& param,
+ int tag, bool marshal) const
+{
+ string helper;
+ BuiltinPtr builtin = BuiltinPtr::dynamicCast(type);
+ ProxyPtr proxy = ProxyPtr::dynamicCast(type);
+ if(builtin)
+ {
+ helper = "ICE" + getBuiltinName(builtin) + "Helper";
+ }
+ else if(proxy)
+ {
+ helper = moduleName(findModule(proxy->_class())) + (proxy->_class()->name()) + "PrxHelper";
+ }
+ else
+ {
+ helper = typeToString(type) + "Helper";
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ out << nl;
+ if(marshal)
+ {
+ out << "[" << helper << " writeOpt:" << param << " stream:os_ tag:" << tag << "];";
+ }
+ else
+ {
+ out << "[" << helper << " readOpt:&" << param << " stream:is_ tag:" << tag << "];";
+ }
+ return;
+ }
+
+ out << nl;
+ if(marshal)
+ {
+ out << "[" << helper << " writeOpt:" << param << " stream:os_ tag:" << tag << "];";
+ }
+ else
+ {
+ out << param << " = [" << helper << " readOpt:is_ tag:" << tag << "];";
+ }
+}
+
+void
+Slice::ObjCGenerator::validateMetaData(const UnitPtr& u)
+{
+ MetaDataVisitor visitor;
+ u->visit(&visitor, true);
+}
+
+const string Slice::ObjCGenerator::MetaDataVisitor::_objcPrefix = "objc:";
+const string Slice::ObjCGenerator::MetaDataVisitor::_msg = "ignoring invalid metadata";
+
+Slice::ObjCGenerator::MetaDataVisitor::MetaDataVisitor()
+{
+}
+
+bool
+Slice::ObjCGenerator::MetaDataVisitor::visitUnitStart(const UnitPtr& p)
+{
+ //
+ // Validate global metadata in the top-level file and all included files.
+ //
+ StringList files = p->allFiles();
+
+ for(StringList::iterator q = files.begin(); q != files.end(); ++q)
+ {
+ string file = *q;
+ DefinitionContextPtr dc = p->findDefinitionContext(file);
+ assert(dc);
+ StringList globalMetaData = dc->getMetaData();
+ int headerDir = 0;
+ for(StringList::const_iterator r = globalMetaData.begin(); r != globalMetaData.end(); ++r)
+ {
+ string s = *r;
+ if(_history.count(s) == 0)
+ {
+ if(s.find(_objcPrefix) == 0)
+ {
+ static const string objcHeaderDirPrefix = "objc:header-dir:";
+ if(s.find(objcHeaderDirPrefix) == 0 && s.size() > objcHeaderDirPrefix.size())
+ {
+ headerDir++;
+ if(headerDir > 1)
+ {
+ ostringstream ostr;
+ ostr << "ignoring invalid global metadata `" << s
+ << "': directive can appear only once per file";
+ emitWarning(file, -1, ostr.str());
+ _history.insert(s);
+ }
+ continue;
+ }
+ ostringstream ostr;
+ ostr << "ignoring invalid global metadata `" << s << "'";
+ emitWarning(file, -1, ostr.str());
+ }
+ _history.insert(s);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+Slice::ObjCGenerator::MetaDataVisitor::visitModuleStart(const ModulePtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitModuleEnd(const ModulePtr&)
+{
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p)
+{
+ validate(p);
+}
+
+bool
+Slice::ObjCGenerator::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&)
+{
+}
+
+bool
+Slice::ObjCGenerator::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&)
+{
+}
+
+bool
+Slice::ObjCGenerator::MetaDataVisitor::visitStructStart(const StructPtr& p)
+{
+ validate(p);
+ return true;
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitStructEnd(const StructPtr&)
+{
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitOperation(const OperationPtr& p)
+{
+ if(p->hasMetaData("UserException"))
+ {
+ ClassDefPtr cl = ClassDefPtr::dynamicCast(p->container());
+ if(!cl->isLocal())
+ {
+ ostringstream os;
+ os << "ignoring invalid metadata `UserException': directive applies only to local operations "
+ << ": warning: metadata directive `UserException' applies only to local operations "
+ << "but enclosing " << (cl->isInterface() ? "interface" : "class") << "`" << cl->name()
+ << "' is not local";
+ emitWarning(p->file(), p->line(), os.str());
+ }
+ }
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitDataMember(const DataMemberPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitSequence(const SequencePtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitDictionary(const DictionaryPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitEnum(const EnumPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::visitConst(const ConstPtr& p)
+{
+ validate(p);
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::validate(const ContainedPtr& cont)
+{
+ ModulePtr m = ModulePtr::dynamicCast(cont);
+ if(m)
+ {
+ bool error = false;
+ bool foundPrefix = false;
+
+ StringList meta = getMetaData(m);
+ StringList::const_iterator p;
+
+ for(p = meta.begin(); p != meta.end(); ++p)
+ {
+ const string prefix = "prefix:";
+ string name;
+ if(p->substr(_objcPrefix.size(), prefix.size()) == prefix)
+ {
+ foundPrefix = true;
+ name = trim(p->substr(_objcPrefix.size() + prefix.size()));
+ if(name.empty())
+ {
+ if(_history.count(*p) == 0)
+ {
+ string file = m->definitionContext()->filename();
+ ostringstream os;
+ os << _msg << " `" << *p << "'" << endl;
+ emitWarning(file, m->line(), os.str());
+ _history.insert(*p);
+ }
+ error = true;
+ }
+ else
+ {
+ if(!addModule(m, name))
+ {
+ modulePrefixError(m, *p);
+ }
+ }
+ }
+ else
+ {
+ if(_history.count(*p) == 0)
+ {
+ string file = m->definitionContext()->filename();
+ ostringstream os;
+ os << _msg << " `" << *p << "'" << endl;
+ emitWarning(file, m->line(), os.str());
+ _history.insert(*p);
+ }
+ error = true;
+ }
+ }
+
+ if(!error && !foundPrefix)
+ {
+ StringList names = splitScopedName(m->scoped());
+ string name;
+ for(StringList::const_iterator i = names.begin(); i != names.end(); ++i)
+ {
+ name += *i;
+ }
+ if(!addModule(m, name))
+ {
+ modulePrefixError(m, "");
+ }
+ }
+ }
+}
+
+StringList
+Slice::ObjCGenerator::MetaDataVisitor::getMetaData(const ContainedPtr& cont)
+{
+ StringList ret;
+ StringList localMetaData = cont->getMetaData();
+ StringList::const_iterator p;
+
+ for(p = localMetaData.begin(); p != localMetaData.end(); ++p)
+ {
+ if(p->find(_objcPrefix) != string::npos)
+ {
+ ret.push_back(*p);
+ }
+ }
+
+ return ret;
+}
+
+void
+Slice::ObjCGenerator::MetaDataVisitor::modulePrefixError(const ModulePtr& m, const string& metadata)
+{
+ string file = m->definitionContext()->filename();
+ string line = m->line();
+ ModulePrefix mp = modulePrefix(m);
+ string old_file = mp.m->definitionContext()->filename();
+ string old_line = mp.m->line();
+ ostringstream os;
+ if(!metadata.empty())
+ {
+ os << _msg << " `" << metadata << "': ";
+ }
+ os << "inconsistent module prefix previously defined ";
+ if(old_file != file)
+ {
+ os << "in " << old_file << ":";
+ }
+ else
+ {
+ os << "at line ";
+ }
+ os << line;
+ os << " as `" << mp.name << "'" << endl;
+ emitWarning(file, line, os.str());
+}
+
diff --git a/cpp/src/Slice/Preprocessor.cpp b/cpp/src/Slice/Preprocessor.cpp
index a5593065d1c..30b6d5c6948 100644
--- a/cpp/src/Slice/Preprocessor.cpp
+++ b/cpp/src/Slice/Preprocessor.cpp
@@ -622,6 +622,16 @@ Slice::Preprocessor::printMakefileDependencies(Language lang, const vector<strin
}
break;
}
+ case ObjC:
+ {
+ string::size_type pos = result.find(suffix);
+ if(pos != string::npos)
+ {
+ string name = result.substr(0, pos);
+ result.replace(0, pos + suffix.size() - 1, name + ".h " + name + ".m");
+ }
+ break;
+ }
default:
{
abort();
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))