diff options
author | Benoit Foucher <benoit@zeroc.com> | 2015-01-07 15:11:14 +0100 |
---|---|---|
committer | Benoit Foucher <benoit@zeroc.com> | 2015-01-07 15:11:14 +0100 |
commit | c126ec03755c9cea578c3b6584ed64c7ba065232 (patch) | |
tree | 453ad5f807fdca1deaa8b16ee62853b414ba1e58 /cpp | |
parent | ICE-6082 added sndBufSize and rcvBufSize to UDPEndpointInfo (diff) | |
download | ice-c126ec03755c9cea578c3b6584ed64c7ba065232.tar.bz2 ice-c126ec03755c9cea578c3b6584ed64c7ba065232.tar.xz ice-c126ec03755c9cea578c3b6584ed64c7ba065232.zip |
Added Objective-C mapping
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/config/Make.rules | 6 | ||||
-rw-r--r-- | cpp/include/Slice/ObjCUtil.h | 125 | ||||
-rw-r--r-- | cpp/include/Slice/Preprocessor.h | 2 | ||||
-rw-r--r-- | cpp/src/Ice/Makefile | 2 | ||||
-rw-r--r-- | cpp/src/Makefile | 14 | ||||
-rw-r--r-- | cpp/src/Slice/Makefile | 1 | ||||
-rw-r--r-- | cpp/src/Slice/ObjCUtil.cpp | 1204 | ||||
-rw-r--r-- | cpp/src/Slice/Preprocessor.cpp | 10 | ||||
-rw-r--r-- | cpp/src/slice2objc/Gen.cpp | 3139 | ||||
-rw-r--r-- | cpp/src/slice2objc/Gen.h | 186 | ||||
-rw-r--r-- | cpp/src/slice2objc/Main.cpp | 290 | ||||
-rw-r--r-- | cpp/src/slice2objc/Makefile | 31 |
12 files changed, 5001 insertions, 9 deletions
diff --git a/cpp/config/Make.rules b/cpp/config/Make.rules index 40dc1c522b8..84b126c37ab 100644 --- a/cpp/config/Make.rules +++ b/cpp/config/Make.rules @@ -358,9 +358,9 @@ ifneq ($(SLICE_OBJS),) endif # -# If dependencies has non been created yet make all OBJS depend -# on all SRCS, Slice generated files will be created before C++ -# compilation starts and avoid problems with parallel make +# If dependencies haven't been created yet make all OBJS depend on all +# SRCS, Slice generated files will be created before C++ compilation +# starts. This prevents issues parallel make. # ifneq ($(OBJS),) diff --git a/cpp/include/Slice/ObjCUtil.h b/cpp/include/Slice/ObjCUtil.h new file mode 100644 index 00000000000..5432259a226 --- /dev/null +++ b/cpp/include/Slice/ObjCUtil.h @@ -0,0 +1,125 @@ +// ********************************************************************** +// +// 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 OBJC_UTIL_H +#define OBJC_UTIL_H + +#include <Slice/Parser.h> +#include <IceUtil/OutputUtil.h> + +namespace Slice +{ + +enum BaseType +{ + BaseTypeNone, + BaseTypeObject, + BaseTypeException +}; + +class SLICE_API ObjCGenerator : private ::IceUtil::noncopyable +{ +public: + + virtual ~ObjCGenerator() {}; + + // + // Validate all metadata in the unit with an "objc:" prefix. + // + static void validateMetaData(const UnitPtr&); + +protected: + struct ModulePrefix + { + ModulePtr m; + std::string name; + }; + + static bool addModule(const ModulePtr&, const std::string&); + static ModulePrefix modulePrefix(const ModulePtr&); + static std::string moduleName(const ModulePtr&); + static ModulePtr findModule(const ContainedPtr&, int = 0, bool = false); + static void modulePrefixError(const ModulePtr&, const std::string&); + static std::string fixId(const std::string&, int = 0, bool = false); + static std::string fixId(const ContainedPtr&, int = 0, bool = false); + static std::string fixName(const ContainedPtr&, int = 0, bool = false); + static std::string fixScoped(const ContainedPtr&, int = 0, bool = false); + static std::string typeToString(const TypePtr&); + static std::string inTypeToString(const TypePtr&, bool, bool = false, bool = false); + static std::string outTypeToString(const TypePtr&, bool, bool = false, bool = false); + static std::string typeToObjCTypeString(const TypePtr&); + static bool isValueType(const TypePtr&); + static bool isString(const TypePtr&); + static bool isClass(const TypePtr&); + static bool mapsToPointerType(const TypePtr&); + static std::string getBuiltinName(const BuiltinPtr&); + static std::string getBuiltinSelector(const BuiltinPtr&, bool); + static std::string getOptionalHelperGetter(const TypePtr&); + static std::string getOptionalStreamHelper(const TypePtr&); + static StringList splitScopedName(const std::string&); + static std::string getOptionalFormat(const TypePtr&); + + // + // Generate code to marshal or unmarshal a type + // + void writeMarshalUnmarshalCode(::IceUtilInternal::Output&, const TypePtr&, const std::string&, bool, bool) const; + void writeOptMemberMarshalUnmarshalCode(::IceUtilInternal::Output&, const TypePtr&, const std::string&, bool) const; + void writeOptParamMarshalUnmarshalCode(::IceUtilInternal::Output&, const TypePtr&, const std::string&, int, + bool) const; + +private: + + class MetaDataVisitor : public ParserVisitor + { + public: + MetaDataVisitor(); + + virtual bool visitUnitStart(const UnitPtr&); + virtual bool visitModuleStart(const ModulePtr&); + virtual void visitModuleEnd(const ModulePtr&); + virtual void visitClassDecl(const ClassDeclPtr&); + virtual bool visitClassDefStart(const ClassDefPtr&); + 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 visitOperation(const OperationPtr&); + virtual void visitParamDecl(const ParamDeclPtr&); + virtual void visitDataMember(const DataMemberPtr&); + virtual void visitSequence(const SequencePtr&); + virtual void visitDictionary(const DictionaryPtr&); + virtual void visitEnum(const EnumPtr&); + virtual void visitConst(const ConstPtr&); + + private: + + void validate(const ContainedPtr&); + + static Slice::StringList getMetaData(const ContainedPtr&); + static void modulePrefixError(const ModulePtr&, const std::string&); + + static const std::string _objcPrefix; // "objc:" + static const std::string _msg; // "ignoring invalid metadata" + + StringSet _history; + }; + + + // + // Map of module scoped name to ModulePtr. Used to verify that objc:prefix metadata directives are consistent. + // + + typedef std::map<std::string, ModulePrefix> ModuleMap; + static ModuleMap _modules; +}; + +} + +#endif diff --git a/cpp/include/Slice/Preprocessor.h b/cpp/include/Slice/Preprocessor.h index 3ae1225a9e0..6667189aec1 100644 --- a/cpp/include/Slice/Preprocessor.h +++ b/cpp/include/Slice/Preprocessor.h @@ -39,7 +39,7 @@ public: FILE* preprocess(bool, const std::string& = ""); bool close(); - enum Language { CPlusPlus, Java, JavaXML, CSharp, Python, Ruby, PHP, JS }; + enum Language { CPlusPlus, Java, JavaXML, CSharp, Python, Ruby, PHP, JS, ObjC }; bool printMakefileDependencies(Language, const std::vector<std::string>&, const std::string& = "", const std::string& = "cpp", const std::string& = ""); 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)) |