diff options
Diffstat (limited to 'cpp/src/slice2cppe/Gen.cpp')
-rw-r--r-- | cpp/src/slice2cppe/Gen.cpp | 4362 |
1 files changed, 4362 insertions, 0 deletions
diff --git a/cpp/src/slice2cppe/Gen.cpp b/cpp/src/slice2cppe/Gen.cpp new file mode 100644 index 00000000000..ef49c9f0eb5 --- /dev/null +++ b/cpp/src/slice2cppe/Gen.cpp @@ -0,0 +1,4362 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2005 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 <Gen.h> +#include <Slice/CPlusPlusUtil.h> +#include <IceUtil/Functional.h> +#include <IceUtil/Iterator.h> +#include <Slice/Checksum.h> + +#include <limits> +#include <sys/stat.h> + +using namespace std; +using namespace Slice; +using namespace IceUtil; + +Slice::Gen::Gen(const string& name, const string& base, const string& headerExtension, + const string& sourceExtension, const string& include, const vector<string>& includePaths, + const string& dllExport, const string& dir, bool imp, bool checksum, bool stream) : + _base(base), + _headerExtension(headerExtension), + _sourceExtension(sourceExtension), + _include(include), + _includePaths(includePaths), + _dllExport(dllExport), + _impl(imp), + _checksum(checksum), + _stream(stream) +{ + for(vector<string>::iterator p = _includePaths.begin(); p != _includePaths.end(); ++p) + { + if(p->length() && (*p)[p->length() - 1] != '/') + { + *p += '/'; + } + } + + string::size_type pos = _base.rfind('/'); + if(pos == string::npos) + { + pos = _base.rfind('\\'); + } + if(pos != string::npos) + { + _base.erase(0, pos + 1); + } + + if(_impl) + { + string fileImplH = _base + "I." + _headerExtension; + string fileImplC = _base + "I." + _sourceExtension; + if(!dir.empty()) + { + fileImplH = dir + '/' + fileImplH; + fileImplC = dir + '/' + fileImplC; + } + + struct stat st; + if(stat(fileImplH.c_str(), &st) == 0) + { + cerr << name << ": `" << fileImplH << "' already exists - will not overwrite" << endl; + return; + } + if(stat(fileImplC.c_str(), &st) == 0) + { + cerr << name << ": `" << fileImplC << "' already exists - will not overwrite" << endl; + return; + } + + implH.open(fileImplH.c_str()); + if(!implH) + { + cerr << name << ": can't open `" << fileImplH << "' for writing" << endl; + return; + } + + implC.open(fileImplC.c_str()); + if(!implC) + { + cerr << name << ": can't open `" << fileImplC << "' for writing" << endl; + return; + } + + string s = fileImplH; + if(_include.size()) + { + s = _include + '/' + s; + } + transform(s.begin(), s.end(), s.begin(), ToIfdef()); + implH << "#ifndef __" << s << "__"; + implH << "\n#define __" << s << "__"; + implH << '\n'; + } + + string fileH = _base + "." + _headerExtension; + string fileC = _base + "." + _sourceExtension; + if(!dir.empty()) + { + fileH = dir + '/' + fileH; + fileC = dir + '/' + fileC; + } + + H.open(fileH.c_str()); + if(!H) + { + cerr << name << ": can't open `" << fileH << "' for writing" << endl; + return; + } + + C.open(fileC.c_str()); + if(!C) + { + cerr << name << ": can't open `" << fileC << "' for writing" << endl; + return; + } + + printHeader(H); + printHeader(C); + H << "\n// Generated from file `" << changeInclude(_base, _includePaths) << ".ice'\n"; + C << "\n// Generated from file `" << changeInclude(_base, _includePaths) << ".ice'\n"; + + string s = fileH; + if(_include.size()) + { + s = _include + '/' + s; + } + transform(s.begin(), s.end(), s.begin(), ToIfdef()); + H << "\n#ifndef __" << s << "__"; + H << "\n#define __" << s << "__"; + H << '\n'; +} + +Slice::Gen::~Gen() +{ + H << "\n\n#endif\n"; + C << '\n'; + + if(_impl) + { + implH << "\n\n#endif\n"; + implC << '\n'; + } +} + +bool +Slice::Gen::operator!() const +{ + if(!H || !C) + { + return true; + } + if(_impl && (!implH || !implC)) + { + return true; + } + return false; +} + +void +Slice::Gen::generate(const UnitPtr& p) +{ + validateMetaData(p); + + C << "\n#include <"; + if(_include.size()) + { + C << _include << '/'; + } + C << _base << "." << _headerExtension << ">"; + + H << "\n#include <Ice/LocalObjectF.h>"; + H << "\n#include <Ice/ProxyF.h>"; + H << "\n#include <Ice/ObjectF.h>"; + H << "\n#include <Ice/Exception.h>"; + H << "\n#include <Ice/LocalObject.h>"; + + if(p->usesProxies()) + { + H << "\n#include <Ice/Proxy.h>"; + } + + if(p->hasNonLocalClassDefs()) + { + H << "\n#include <Ice/Object.h>"; + H << "\n#include <Ice/Outgoing.h>"; + if(p->hasContentsWithMetaData("ami")) + { + H << "\n#include <Ice/OutgoingAsync.h>"; + } + H << "\n#include <Ice/Incoming.h>"; + if(p->hasContentsWithMetaData("amd")) + { + H << "\n#include <Ice/IncomingAsync.h>"; + } + H << "\n#include <Ice/Direct.h>"; + C << "\n#include <Ice/LocalException.h>"; + C << "\n#include <Ice/ObjectFactory.h>"; + } + + if(p->hasNonLocalExceptions()) + { + H << "\n#include <Ice/UserExceptionFactory.h>"; + } + + if(p->hasDataOnlyClasses() || p->hasNonLocalExceptions()) + { + H << "\n#include <Ice/FactoryTable.h>"; + } + + if(p->usesNonLocals()) + { + C << "\n#include <Ice/BasicStream.h>"; + C << "\n#include <Ice/Object.h>"; + } + + if(_stream || p->hasNonLocalClassDefs() || p->hasNonLocalExceptions()) + { + H << "\n#include <Ice/StreamF.h>"; + + if(!p->hasNonLocalClassDefs()) + { + C << "\n#include <Ice/LocalException.h>"; + } + + if(_stream) + { + C << "\n#include <Ice/Stream.h>"; + } + } + + if(_checksum) + { + C << "\n#include <Ice/SliceChecksums.h>"; + } + + StringList includes = p->includeFiles(); + + for(StringList::const_iterator q = includes.begin(); q != includes.end(); ++q) + { + H << "\n#include <" << changeInclude(*q, _includePaths) << "." << _headerExtension << ">"; + } + + printVersionCheck(H); + printVersionCheck(C); + + printDllExportStuff(H, _dllExport); + if(_dllExport.size()) + { + _dllExport += " "; + } + + ProxyDeclVisitor proxyDeclVisitor(H, C, _dllExport); + p->visit(&proxyDeclVisitor, false); + + ObjectDeclVisitor objectDeclVisitor(H, C, _dllExport); + p->visit(&objectDeclVisitor, false); + + IceInternalVisitor iceInternalVisitor(H, C, _dllExport); + p->visit(&iceInternalVisitor, false); + + HandleVisitor handleVisitor(H, C, _dllExport, _stream); + p->visit(&handleVisitor, false); + + TypesVisitor typesVisitor(H, C, _dllExport, _stream); + p->visit(&typesVisitor, false); + + AsyncVisitor asyncVisitor(H, C, _dllExport); + p->visit(&asyncVisitor, false); + + AsyncImplVisitor asyncImplVisitor(H, C, _dllExport); + p->visit(&asyncImplVisitor, false); + + ProxyVisitor proxyVisitor(H, C, _dllExport); + p->visit(&proxyVisitor, false); + + DelegateVisitor delegateVisitor(H, C, _dllExport); + p->visit(&delegateVisitor, false); + + DelegateMVisitor delegateMVisitor(H, C, _dllExport); + p->visit(&delegateMVisitor, false); + + DelegateDVisitor delegateDVisitor(H, C, _dllExport); + p->visit(&delegateDVisitor, false); + + ObjectVisitor objectVisitor(H, C, _dllExport, _stream); + p->visit(&objectVisitor, false); + + if(_impl) + { + implH << "\n#include <"; + if(_include.size()) + { + implH << _include << '/'; + } + implH << _base << ".h>"; + + implC << "#include <"; + if(_include.size()) + { + implC << _include << '/'; + } + implC << _base << "I.h>"; + + ImplVisitor implVisitor(implH, implC, _dllExport); + p->visit(&implVisitor, false); + } + + if(_checksum) + { + ChecksumMap map = createChecksums(p); + if(!map.empty()) + { + C << sp << nl << "static const char* __sliceChecksums[] ="; + C << sb; + for(ChecksumMap::const_iterator p = map.begin(); p != map.end(); ++p) + { + C << nl << "\"" << p->first << "\", \""; + ostringstream str; + str.flags(ios_base::hex); + str.fill('0'); + for(vector<unsigned char>::const_iterator q = p->second.begin(); q != p->second.end(); ++q) + { + str << (int)(*q); + } + C << str.str() << "\","; + } + C << nl << "0"; + C << eb << ';'; + C << nl << "static IceInternal::SliceChecksumInit __sliceChecksumInit(__sliceChecksums);"; + } + } +} + +Slice::Gen::TypesVisitor::TypesVisitor(Output& h, Output& c, const string& dllExport, bool stream) : + H(h), C(c), _dllExport(dllExport), _stream(stream) +{ +} + +bool +Slice::Gen::TypesVisitor::visitModuleStart(const ModulePtr& p) +{ + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::TypesVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::TypesVisitor::visitClassDefStart(const ClassDefPtr&) +{ + return false; +} + +bool +Slice::Gen::TypesVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + ExceptionPtr base = p->base(); + + H << sp << nl << "class " << _dllExport << name << " : "; + H.useCurrentPosAsIndent(); + if(!base) + { + if(p->isLocal()) + { + H << "public ::Ice::LocalException"; + } + else + { + H << "public ::Ice::UserException"; + } + } + else + { + H << "public " << fixKwd(base->scoped()); + } + H.restoreIndent(); + H << sb; + + H.dec(); + H << nl << "public:"; + H.inc(); + + H << sp; + if(p->isLocal()) + { + H << nl << name << "(const char*, int);"; + C << sp << nl << scoped.substr(2) << "::" << name << "(const char* file, int line) : "; + C.inc(); + if(!base) + { + C << nl << "::Ice::LocalException(file, line)"; + } + else + { + C << nl << fixKwd(base->scoped()) << "(file, line)"; + } + C.dec(); + C << sb; + C << eb; + } + + H << nl << "virtual const ::std::string& ice_name() const;"; + + string flatName = p->flattenedScope() + p->name() + "_name"; + + C << sp << nl << "static const ::std::string " << flatName << " = \"" << p->scoped().substr(2) << "\";"; + C << sp << nl << "const ::std::string&" << nl << scoped.substr(2) << "::ice_name() const"; + C << sb; + C << nl << "return " << flatName << ';'; + C << eb; + + if(p->isLocal()) + { + H << nl << "virtual void ice_print(::std::ostream&) const;"; + } + + H << nl << "virtual ::Ice::Exception* ice_clone() const;"; + C << sp << nl << "::Ice::Exception*" << nl << scoped.substr(2) << "::ice_clone() const"; + C << sb; + C << nl << "return new " << name << "(*this);"; + C << eb; + + H << nl << "virtual void ice_throw() const;"; + C << sp << nl << "void" << nl << scoped.substr(2) << "::ice_throw() const"; + C << sb; + C << nl << "throw *this;"; + C << eb; + + if(!p->isLocal()) + { + H << sp << nl << "static const ::IceInternal::UserExceptionFactoryPtr& ice_factory();"; + } + return true; +} + +void +Slice::Gen::TypesVisitor::visitExceptionEnd(const ExceptionPtr& p) +{ + string name = fixKwd(p->name()); + string scope = fixKwd(p->scope()); + string scoped = fixKwd(p->scoped()); + DataMemberList dataMembers = p->dataMembers(); + DataMemberList::const_iterator q; + + string factoryName; + + if(!p->isLocal()) + { + ExceptionPtr base = p->base(); + + H << sp << nl << "virtual void __write(::IceInternal::BasicStream*) const;"; + H << nl << "virtual void __read(::IceInternal::BasicStream*, bool);"; + + H << sp << nl << "virtual void __write(const ::Ice::OutputStreamPtr&) const;"; + H << nl << "virtual void __read(const ::Ice::InputStreamPtr&, bool);"; + + TypeStringList memberList; + for(q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + memberList.push_back(make_pair((*q)->type(), (*q)->name())); + } + C << sp << nl << "void" << nl << scoped.substr(2) << "::__write(::IceInternal::BasicStream* __os) const"; + C << sb; + C << nl << "__os->write(::std::string(\"" << p->scoped() << "\"));"; + C << nl << "__os->startWriteSlice();"; + writeMarshalCode(C, memberList, 0); + C << nl << "__os->endWriteSlice();"; + if(base) + { + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << fixKwd(base->name()) << "::__write(__os);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << fixKwd(base->scoped()) << "::__write(__os);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + } + C << eb; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__read(::IceInternal::BasicStream* __is, bool __rid)"; + C << sb; + C << nl << "if(__rid)"; + C << sb; + C << nl << "::std::string myId;"; + C << nl << "__is->read(myId);"; + C << eb; + C << nl << "__is->startReadSlice();"; + writeUnmarshalCode(C, memberList, 0); + C << nl << "__is->endReadSlice();"; + if(base) + { + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << fixKwd(base->name()) << "::__read(__is, true);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << fixKwd(base->scoped()) << "::__read(__is, true);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + } + C << eb; + + if(_stream) + { + C << sp << nl << "void" << nl << scoped.substr(2) << "::__write(const ::Ice::OutputStreamPtr& __out) const"; + C << sb; + C << nl << "__out->writeString(::std::string(\"" << p->scoped() << "\"));"; + C << nl << "__out->startSlice();"; + writeStreamMarshalCode(C, memberList, 0); + C << nl << "__out->endSlice();"; + if(base) + { + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << fixKwd(base->name()) << "::__write(__out);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << fixKwd(base->scoped()) << "::__write(__out);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + } + C << eb; + + C << sp << nl << "void" << nl << scoped.substr(2) + << "::__read(const ::Ice::InputStreamPtr& __in, bool __rid)"; + C << sb; + C << nl << "if(__rid)"; + C << sb; + C << nl << "__in->readString();"; + C << eb; + C << nl << "__in->startSlice();"; + writeStreamUnmarshalCode(C, memberList, 0); + C << nl << "__in->endSlice();"; + if(base) + { + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << fixKwd(base->name()) << "::__read(__in, true);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << fixKwd(base->scoped()) << "::__read(__in, true);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + } + C << eb; + } + else + { + // + // Emit placeholder functions to catch errors. + // + C << sp << nl << "void" << nl << scoped.substr(2) << "::__write(const ::Ice::OutputStreamPtr&) const"; + C << sb; + C << nl << "Ice::MarshalException ex(__FILE__, __LINE__);"; + C << nl << "ex.reason = \"exception " << scoped.substr(2) << " was not generated with stream support\";"; + C << nl << "throw ex;"; + C << eb; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__read(const ::Ice::InputStreamPtr&, bool)"; + C << sb; + C << nl << "Ice::MarshalException ex(__FILE__, __LINE__);"; + C << nl << "ex.reason = \"exception " << scoped .substr(2)<< " was not generated with stream support\";"; + C << nl << "throw ex;"; + C << eb; + } + + if(p->usesClasses()) + { + if(!base || (base && !base->usesClasses())) + { + H << nl << "virtual bool __usesClasses() const;"; + + C << sp << nl << "bool"; + C << nl << scoped.substr(2) << "::__usesClasses() const"; + C << sb; + C << nl << "return true;"; + C << eb; + } + } + + factoryName = "__F" + p->flattenedScope() + p->name(); + + C << sp << nl << "struct " << factoryName << " : public ::IceInternal::UserExceptionFactory"; + C << sb; + C << sp << nl << "virtual void"; + C << nl << "createAndThrow()"; + C << sb; + C << nl << "throw " << scoped << "();"; + C << eb; + C << eb << ';'; + + C << sp << nl << "static ::IceInternal::UserExceptionFactoryPtr " << factoryName + << "__Ptr = new " << factoryName << ';'; + + C << sp << nl << "const ::IceInternal::UserExceptionFactoryPtr&"; + C << nl << scoped.substr(2) << "::ice_factory()"; + C << sb; + C << nl << "return " << factoryName << "__Ptr;"; + C << eb; + + C << sp << nl << "class " << factoryName << "__Init"; + C << sb; + C.dec(); + C << nl << "public:"; + C.inc(); + C << sp << nl << factoryName << "__Init()"; + C << sb; + C << nl << "::Ice::factoryTable->addExceptionFactory(\"" << p->scoped() << "\", " << scoped + << "::ice_factory());"; + C << eb; + C << sp << nl << "~" << factoryName << "__Init()"; + C << sb; + C << nl << "::Ice::factoryTable->removeExceptionFactory(\"" << p->scoped() << "\");"; + C << eb; + C << eb << ';'; + C << sp << nl << "static " << factoryName << "__Init "<< factoryName << "__i;"; + C << sp << nl << "#ifdef __APPLE__"; + + string initfuncname = "__F" + p->flattenedScope() + p->name() + "__initializer"; + C << nl << "extern \"C\" { void " << initfuncname << "() {} }"; + C << nl << "#endif"; + } + H << eb << ';'; + + if(!p->isLocal()) + { + H << sp << nl << "static " << name << " __" << p->name() << "_init;"; + } +} + +bool +Slice::Gen::TypesVisitor::visitStructStart(const StructPtr& p) +{ + string name = fixKwd(p->name()); + + H << sp << nl << "struct " << name; + H << sb; + + return true; +} + +void +Slice::Gen::TypesVisitor::visitStructEnd(const StructPtr& p) +{ + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + H << sp; + H << nl << _dllExport << "bool operator==(const " << name << "&) const;"; + H << nl << _dllExport << "bool operator!=(const " << name << "&) const;"; + H << nl << _dllExport << "bool operator<(const " << name << "&) const;"; + + DataMemberList dataMembers = p->dataMembers(); + DataMemberList::const_iterator q; + C << sp << nl << "bool" << nl << scoped.substr(2) << "::operator==(const " << name << "& __rhs) const"; + C << sb; + C << nl << "return !operator!=(__rhs);"; + C << eb; + C << sp << nl << "bool" << nl << scoped.substr(2) << "::operator!=(const " << name << "& __rhs) const"; + C << sb; + C << nl << "if(this == &__rhs)"; + C << sb; + C << nl << "return false;"; + C << eb; + for(q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + C << nl << "if(" << fixKwd((*q)->name()) << " != __rhs." << fixKwd((*q)->name()) << ')'; + C << sb; + C << nl << "return true;"; + C << eb; + } + C << nl << "return false;"; + C << eb; + C << sp << nl << "bool" << nl << scoped.substr(2) << "::operator<(const " << name << "& __rhs) const"; + C << sb; + C << nl << "if(this == &__rhs)"; + C << sb; + C << nl << "return false;"; + C << eb; + for(q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + C << nl << "if(" << fixKwd((*q)->name()) << " < __rhs." << fixKwd((*q)->name()) << ')'; + C << sb; + C << nl << "return true;"; + C << eb; + C << nl << "else if(__rhs." << fixKwd((*q)->name()) << " < " << fixKwd((*q)->name()) << ')'; + C << sb; + C << nl << "return false;"; + C << eb; + } + C << nl << "return false;"; + C << eb; + + if(!p->isLocal()) + { + // + // None of these member functions is virtual! + // + H << sp << nl << _dllExport << "void __write(::IceInternal::BasicStream*) const;"; + H << nl << _dllExport << "void __read(::IceInternal::BasicStream*);"; + + if(_stream) + { + H << sp << nl << _dllExport << "void __write(const ::Ice::OutputStreamPtr&) const;"; + H << nl << _dllExport << "void __read(const ::Ice::InputStreamPtr&);"; + } + + TypeStringList memberList; + for(q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + memberList.push_back(make_pair((*q)->type(), (*q)->name())); + } + C << sp << nl << "void" << nl << scoped.substr(2) << "::__write(::IceInternal::BasicStream* __os) const"; + C << sb; + writeMarshalCode(C, memberList, 0); + C << eb; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__read(::IceInternal::BasicStream* __is)"; + C << sb; + writeUnmarshalCode(C, memberList, 0); + C << eb; + + if(_stream) + { + C << sp << nl << "void" << nl << scoped.substr(2) << "::__write(const ::Ice::OutputStreamPtr& __out) const"; + C << sb; + writeStreamMarshalCode(C, memberList, 0); + C << eb; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__read(const ::Ice::InputStreamPtr& __in)"; + C << sb; + writeStreamUnmarshalCode(C, memberList, 0); + C << eb; + } + } + + H << eb << ';'; + + if(!p->isLocal() && _stream) + { + H << sp << nl << _dllExport << "void ice_write" << p->name() << "(const ::Ice::OutputStreamPtr&, const " + << name << "&);"; + H << nl << _dllExport << "void ice_read" << p->name() << "(const ::Ice::InputStreamPtr&, " << name << "&);"; + + C << sp << nl << "void" << nl << scope.substr(2) << "ice_write" << p->name() + << "(const ::Ice::OutputStreamPtr& __out, const " << scoped << "& __v)"; + C << sb; + C << nl << "__v.__write(__out);"; + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "ice_read" << p->name() + << "(const ::Ice::InputStreamPtr& __in, " << scoped << "& __v)"; + C << sb; + C << nl << "__v.__read(__in);"; + C << eb; + } +} + +void +Slice::Gen::TypesVisitor::visitDataMember(const DataMemberPtr& p) +{ + string name = fixKwd(p->name()); + string s = typeToString(p->type()); + H << sp << nl << s << ' ' << name << ';'; +} + +void +Slice::Gen::TypesVisitor::visitSequence(const SequencePtr& p) +{ + string name = fixKwd(p->name()); + TypePtr type = p->type(); + string s = typeToString(type); + if(s[0] == ':') + { + s.insert(0, " "); + } + H << sp << nl << "typedef ::std::vector<" << s << "> " << name << ';'; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(!p->isLocal() && + (!builtin || builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindObjectProxy)) + { + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + H << sp << nl << "class __U__" << name << " { };"; + H << nl << _dllExport << "void __write(::IceInternal::BasicStream*, const " << name << "&, __U__" << name + << ");"; + H << nl << _dllExport << "void __read(::IceInternal::BasicStream*, " << name << "&, __U__" << name << ");"; + + if(_stream) + { + H << nl << _dllExport << "void ice_write" << p->name() << "(const ::Ice::OutputStreamPtr&, const " + << name << "&);"; + H << nl << _dllExport << "void ice_read" << p->name() << "(const ::Ice::InputStreamPtr&, " << name << "&);"; + } + + C << sp << nl << "void" << nl << scope.substr(2) << "__write(::IceInternal::BasicStream* __os, const " + << scoped << "& v, " << scope << "__U__" << name << ")"; + C << sb; + C << nl << "__os->writeSize(::Ice::Int(v.size()));"; + C << nl << scoped << "::const_iterator p;"; + C << nl << "for(p = v.begin(); p != v.end(); ++p)"; + C << sb; + writeMarshalUnmarshalCode(C, type, "(*p)", true); + C << eb; + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "__read(::IceInternal::BasicStream* __is, " << scoped + << "& v, " << scope << "__U__" << name << ')'; + C << sb; + C << nl << "::Ice::Int sz;"; + C << nl << "__is->readSize(sz);"; + if(type->isVariableLength()) + { + C << nl << "__is->startSeq(sz, " << type->minWireSize() << ");"; // Protect against bogus sequence sizes. + } + else + { + C << nl << "__is->checkFixedSeq(sz, " << type->minWireSize() << ");"; + } + C << nl << "v.resize(sz);"; + C << nl << "for(int i = 0; i < sz; ++i)"; + C << sb; + writeMarshalUnmarshalCode(C, type, "v[i]", false); + + // + // After unmarshaling each element, check that there are still enough bytes left in the stream + // to unmarshal the remainder of the sequence, and decrement the count of elements + // yet to be unmarshaled for sequences with variable-length element type (that is, for sequences + // of classes, structs, dictionaries, sequences, strings, or proxies). This allows us to + // abort unmarshaling for bogus sequence sizes at the earliest possible moment. + // (For fixed-length sequences, we don't need to do this because the prediction of how many + // bytes will be taken up by the sequence is accurate.) + // + if(type->isVariableLength()) + { + if(!SequencePtr::dynamicCast(type)) + { + // + // No need to check for directly nested sequences because, at the start of each + // sequence, we check anyway. + // + C << nl << "__is->checkSeq();"; + } + C << nl << "__is->endElement();"; + } + C << eb; + if(type->isVariableLength()) + { + C << nl << "__is->endSeq(sz);"; + } + C << eb; + + if(_stream) + { + C << sp << nl << "void" << nl << scope.substr(2) << "ice_write" << p->name() + << "(const ::Ice::OutputStreamPtr& __out, const " << scoped << "& v)"; + C << sb; + C << nl << "__out->writeSize(::Ice::Int(v.size()));"; + C << nl << scoped << "::const_iterator p;"; + C << nl << "for(p = v.begin(); p != v.end(); ++p)"; + C << sb; + writeStreamMarshalUnmarshalCode(C, type, "(*p)", true); + C << eb; + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "ice_read" << p->name() + << "(const ::Ice::InputStreamPtr& __in, " << scoped << "& v)"; + C << sb; + C << nl << "::Ice::Int sz = __in->readSize();"; + C << nl << "v.resize(sz);"; + C << nl << "for(int i = 0; i < sz; ++i)"; + C << sb; + writeStreamMarshalUnmarshalCode(C, type, "v[i]", false); + C << eb; + C << eb; + } + } +} + +void +Slice::Gen::TypesVisitor::visitDictionary(const DictionaryPtr& p) +{ + string name = fixKwd(p->name()); + TypePtr keyType = p->keyType(); + TypePtr valueType = p->valueType(); + string ks = typeToString(keyType); + if(ks[0] == ':') + { + ks.insert(0, " "); + } + string vs = typeToString(valueType); + H << sp << nl << "typedef ::std::map<" << ks << ", " << vs << "> " << name << ';'; + + if(!p->isLocal()) + { + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + H << sp << nl << "class __U__" << name << " { };"; + H << nl << _dllExport << "void __write(::IceInternal::BasicStream*, const " << name + << "&, __U__" << name << ");"; + H << nl << _dllExport << "void __read(::IceInternal::BasicStream*, " << name + << "&, __U__" << name << ");"; + + if(_stream) + { + H << nl << _dllExport << "void ice_write" << p->name() << "(const ::Ice::OutputStreamPtr&, const " << name + << "&);"; + H << nl << _dllExport << "void ice_read" << p->name() << "(const ::Ice::InputStreamPtr&, " << name << "&);"; + } + + C << sp << nl << "void" << nl << scope.substr(2) << "__write(::IceInternal::BasicStream* __os, const " + << scoped << "& v, " << scope << "__U__" << name << ")"; + C << sb; + C << nl << "__os->writeSize(::Ice::Int(v.size()));"; + C << nl << scoped << "::const_iterator p;"; + C << nl << "for(p = v.begin(); p != v.end(); ++p)"; + C << sb; + writeMarshalUnmarshalCode(C, keyType, "p->first", true); + writeMarshalUnmarshalCode(C, valueType, "p->second", true); + C << eb; + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "__read(::IceInternal::BasicStream* __is, " << scoped + << "& v, " << scope << "__U__" << name << ')'; + C << sb; + C << nl << "::Ice::Int sz;"; + C << nl << "__is->readSize(sz);"; + C << nl << "while(sz--)"; + C << sb; + C << nl << "::std::pair<const " << ks << ", " << vs << "> pair;"; + string pf = string("const_cast<") + ks + "&>(pair.first)"; + writeMarshalUnmarshalCode(C, keyType, pf, false); + C << nl << scoped << "::iterator __i = v.insert(v.end(), pair);"; + writeMarshalUnmarshalCode(C, valueType, "__i->second", false); + C << eb; + C << eb; + + if(_stream) + { + C << sp << nl << "void" << nl << scope.substr(2) << "ice_write" << p->name() + << "(const ::Ice::OutputStreamPtr& __out, const " << scoped << "& v)"; + C << sb; + C << nl << "__out->writeSize(::Ice::Int(v.size()));"; + C << nl << scoped << "::const_iterator p;"; + C << nl << "for(p = v.begin(); p != v.end(); ++p)"; + C << sb; + writeStreamMarshalUnmarshalCode(C, keyType, "p->first", true); + writeStreamMarshalUnmarshalCode(C, valueType, "p->second", true); + C << eb; + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "ice_read" << p->name() + << "(const ::Ice::InputStreamPtr& __in, " << scoped << "& v)"; + C << sb; + C << nl << "::Ice::Int sz = __in->readSize();"; + C << nl << "while(sz--)"; + C << sb; + C << nl << "::std::pair<const " << ks << ", " << vs << "> pair;"; + string pf = string("const_cast<") + ks + "&>(pair.first)"; + writeStreamMarshalUnmarshalCode(C, keyType, pf, false); + C << nl << scoped << "::iterator __i = v.insert(v.end(), pair);"; + writeStreamMarshalUnmarshalCode(C, valueType, "__i->second", false); + C << eb; + C << eb; + } + } +} + +void +Slice::Gen::TypesVisitor::visitEnum(const EnumPtr& p) +{ + string name = fixKwd(p->name()); + EnumeratorList enumerators = p->getEnumerators(); + H << sp << nl << "enum " << name; + H << sb; + EnumeratorList::const_iterator en = enumerators.begin(); + while(en != enumerators.end()) + { + H << nl << fixKwd((*en)->name()); + if(++en != enumerators.end()) + { + H << ','; + } + } + H << eb << ';'; + + if(!p->isLocal()) + { + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + size_t sz = enumerators.size(); + assert(sz <= 0x7fffffff); // 64-bit enums are not supported + + H << sp << nl << _dllExport << "void __write(::IceInternal::BasicStream*, " << name << ");"; + H << nl << _dllExport << "void __read(::IceInternal::BasicStream*, " << name << "&);"; + + if(_stream) + { + H << sp << nl << _dllExport << "void ice_write" << p->name() + << "(const ::Ice::OutputStreamPtr&, " << name << ");"; + H << nl << _dllExport << "void ice_read" << p->name() << "(const ::Ice::InputStreamPtr&, " << name << "&);"; + } + + C << sp << nl << "void" << nl << scope.substr(2) << "__write(::IceInternal::BasicStream* __os, " << scoped + << " v)"; + C << sb; + if(sz <= 0x7f) + { + C << nl << "__os->write(static_cast< ::Ice::Byte>(v));"; + } + else if(sz <= 0x7fff) + { + C << nl << "__os->write(static_cast< ::Ice::Short>(v));"; + } + else + { + C << nl << "__os->write(static_cast< ::Ice::Int>(v));"; + } + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "__read(::IceInternal::BasicStream* __is, " << scoped + << "& v)"; + C << sb; + if(sz <= 0x7f) + { + C << nl << "::Ice::Byte val;"; + C << nl << "__is->read(val);"; + C << nl << "v = static_cast< " << scoped << ">(val);"; + } + else if(sz <= 0x7fff) + { + C << nl << "::Ice::Short val;"; + C << nl << "__is->read(val);"; + C << nl << "v = static_cast< " << scoped << ">(val);"; + } + else + { + C << nl << "::Ice::Int val;"; + C << nl << "__is->read(val);"; + C << nl << "v = static_cast< " << scoped << ">(val);"; + } + C << eb; + + if(_stream) + { + C << sp << nl << "void" << nl << scope.substr(2) << "ice_write" << p->name() + << "(const ::Ice::OutputStreamPtr& __out, " << scoped << " v)"; + C << sb; + if(sz <= 0x7f) + { + C << nl << "__out->writeByte(static_cast< ::Ice::Byte>(v));"; + } + else if(sz <= 0x7fff) + { + C << nl << "__out->writeShort(static_cast< ::Ice::Short>(v));"; + } + else + { + C << nl << "__out->writeInt(static_cast< ::Ice::Int>(v));"; + } + C << eb; + + C << sp << nl << "void" << nl << scope.substr(2) << "ice_read" << p->name() + << "(const ::Ice::InputStreamPtr& __in, " << scoped << "& v)"; + C << sb; + if(sz <= 0x7f) + { + C << nl << "::Ice::Byte val = __in->readByte();"; + C << nl << "v = static_cast< " << scoped << ">(val);"; + } + else if(sz <= 0x7fff) + { + C << nl << "::Ice::Short val = __in->readShort();"; + C << nl << "v = static_cast< " << scoped << ">(val);"; + } + else + { + C << nl << "::Ice::Int val = __in->readInt();"; + C << nl << "v = static_cast< " << scoped << ">(val);"; + } + C << eb; + } + } +} + +void +Slice::Gen::TypesVisitor::visitConst(const ConstPtr& p) +{ + H << sp; + H << nl << "const " << typeToString(p->type()) << " " << fixKwd(p->name()) << " = "; + + BuiltinPtr bp = BuiltinPtr::dynamicCast(p->type()); + if(bp && bp->kind() == Builtin::KindString) + { + // + // 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" + "_{}[]#()<>%:;,?*+=/^&|~!=,\\\"' \t"; + static const set<char> charSet(basicSourceChars.begin(), basicSourceChars.end()); + + H << "\""; // Opening " + + ios_base::fmtflags originalFlags = H.flags(); // Save stream state + streamsize originalWidth = H.width(); + ostream::char_type originalFill = H.fill(); + + const string val = p->value(); + 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 + H << "\\"; // Print as octal if not in basic source character set + H.flags(ios_base::oct); + H.width(3); + H.fill('0'); + H << static_cast<unsigned>(uc); + } + else + { + H << *c; // Print normally if in basic source character set + } + } + + H.fill(originalFill); // Restore stream state + H.width(originalWidth); + H.flags(originalFlags); + + H << "\""; // Closing " + } + else if(bp && bp->kind() == Builtin::KindLong) + { + H << "ICE_INT64(" << p->value() << ")"; + } + else + { + EnumPtr ep = EnumPtr::dynamicCast(p->type()); + if(ep) + { + H << fixKwd(p->value()); + } + else + { + H << p->value(); + } + } + + H << ';'; +} + +Slice::Gen::ProxyDeclVisitor::ProxyDeclVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::ProxyDeclVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + H << sp << nl << "namespace IceProxy" << nl << '{'; + + return true; +} + +void +Slice::Gen::ProxyDeclVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::ProxyDeclVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::ProxyDeclVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +void +Slice::Gen::ProxyDeclVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + if(p->isLocal()) + { + return; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "class " << name << ';'; + H << nl << _dllExport << "bool operator==(const " << name << "&, const " << name << "&);"; + H << nl << _dllExport << "bool operator!=(const " << name << "&, const " << name << "&);"; + H << nl << _dllExport << "bool operator<(const " << name << "&, const " << name << "&);"; +} + +Slice::Gen::ProxyVisitor::ProxyVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::ProxyVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + H << sp << nl << "namespace IceProxy" << nl << '{'; + + return true; +} + +void +Slice::Gen::ProxyVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::ProxyVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::ProxyVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::ProxyVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) + { + return false; + } + + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + ClassList bases = p->bases(); + + H << sp << nl << "class " << _dllExport << name << " : "; + if(bases.empty()) + { + H << "virtual public ::IceProxy::Ice::Object"; + } + else + { + H.useCurrentPosAsIndent(); + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + H << "virtual public ::IceProxy" << fixKwd((*q)->scoped()); + if(++q != bases.end()) + { + H << ',' << nl; + } + } + H.restoreIndent(); + } + + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + return true; +} + +void +Slice::Gen::ProxyVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + H << nl << nl << "static const ::std::string& ice_staticId();"; + + H.dec(); + H << sp << nl << "private: "; + H.inc(); + H << sp << nl << "virtual ::IceInternal::Handle< ::IceDelegateM::Ice::Object> __createDelegateM();"; + H << nl << "virtual ::IceInternal::Handle< ::IceDelegateD::Ice::Object> __createDelegateD();"; + H << eb << ';'; + + C << sp; + C << nl << "const ::std::string&" << nl << "IceProxy" << scoped << "::ice_staticId()"; + C << sb; + C << nl << "return "<< scoped << "::ice_staticId();"; + C << eb; + + C << sp << nl << "::IceInternal::Handle< ::IceDelegateM::Ice::Object>"; + C << nl << "IceProxy" << scoped << "::__createDelegateM()"; + C << sb; + C << nl << "return ::IceInternal::Handle< ::IceDelegateM::Ice::Object>(new ::IceDelegateM" << scoped << ");"; + C << eb; + C << sp << nl << "::IceInternal::Handle< ::IceDelegateD::Ice::Object>"; + C << nl << "IceProxy" << scoped << "::__createDelegateD()"; + C << sb; + C << nl << "return ::IceInternal::Handle< ::IceDelegateD::Ice::Object>(new ::IceDelegateD" << scoped << ");"; + C << eb; + + C << sp; + C << nl << "bool" << nl << "IceProxy" << scope << "operator==(const ::IceProxy" << scoped + << "& l, const ::IceProxy" << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::IceProxy::Ice::Object&>(l) == " + << "static_cast<const ::IceProxy::Ice::Object&>(r);"; + C << eb; + C << sp; + C << nl << "bool" << nl << "IceProxy" << scope << "operator!=(const ::IceProxy" << scoped + << "& l, const ::IceProxy" << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::IceProxy::Ice::Object&>(l) != " + << "static_cast<const ::IceProxy::Ice::Object&>(r);"; + C << eb; + C << sp; + C << nl << "bool" << nl << "IceProxy" << scope << "operator<(const ::IceProxy" << scoped + << "& l, const ::IceProxy" << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::IceProxy::Ice::Object&>(l) < " + << "static_cast<const ::IceProxy::Ice::Object&>(r);"; + C << eb; +} + +void +Slice::Gen::ProxyVisitor::visitOperation(const OperationPtr& p) +{ + string name = p->name(); + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + TypePtr ret = p->returnType(); + string retS = returnTypeToString(ret); + + vector<string> params; + vector<string> paramsDecl; + vector<string> args; + + vector<string> paramsAMI; + vector<string> paramsDeclAMI; + vector<string> argsAMI; + + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string paramName = fixKwd((*q)->name()); + +#if defined(__SUNPRO_CC) && (__SUNPRO_CC==0x550) + // + // Work around for Sun CC 5.5 bug #4853566 + // + string typeString; + if((*q)->isOutParam()) + { + typeString = outputTypeToString((*q)->type()); + } + else + { + typeString = inputTypeToString((*q)->type()); + } +#else + string typeString = (*q)->isOutParam() ? outputTypeToString((*q)->type()) : inputTypeToString((*q)->type()); +#endif + + params.push_back(typeString); + paramsDecl.push_back(typeString + ' ' + paramName); + args.push_back(paramName); + + if(!(*q)->isOutParam()) + { + string inputTypeString = inputTypeToString((*q)->type()); + + paramsAMI.push_back(inputTypeString); + paramsDeclAMI.push_back(inputTypeString + ' ' + paramName); + argsAMI.push_back(paramName); + } + } + + string thisPointer = fixKwd(scope.substr(0, scope.size() - 2)) + "*"; + + H << sp; + H << nl << retS << ' ' << fixKwd(name) << spar << params << epar << ';'; + H << nl << retS << ' ' << fixKwd(name) << spar << params << "const ::Ice::Context&" << epar << ';'; + + C << sp << nl << retS << nl << "IceProxy" << scoped << spar << paramsDecl << epar; + C << sb; + C << nl; + if(ret) + { + C << "return "; + } + C << fixKwd(name) << spar << args << "__defaultContext()" << epar << ';'; + C << eb; + + C << sp << nl << retS << nl << "IceProxy" << scoped << spar << paramsDecl << "const ::Ice::Context& __ctx" << epar; + C << sb; + C << nl << "int __cnt = 0;"; + C << nl << "while(true)"; + C << sb; + C << nl << "try"; + C << sb; + if(p->returnsData()) + { + C << nl << "__checkTwowayOnly(\"" << name << "\");"; + } + C << nl << "::IceInternal::Handle< ::IceDelegate::Ice::Object> __delBase = __getDelegate();"; + C << nl << "::IceDelegate" << thisPointer << " __del = dynamic_cast< ::IceDelegate" + << thisPointer << ">(__delBase.get());"; + C << nl; + if(ret) + { + C << "return "; + } + C << "__del->" << fixKwd(name) << spar << args << "__ctx" << epar << ';'; + if(!ret) + { + C << nl << "return;"; + } + C << eb; + C << nl << "catch(const ::IceInternal::NonRepeatable& __ex)"; + C << sb; + if(p->mode() == Operation::Idempotent || p->mode() == Operation::Nonmutating) + { + C << nl << "__handleException(*__ex.get(), __cnt);"; + } + else + { + C << nl << "__rethrowException(*__ex.get());"; + } + C << eb; + C << nl << "catch(const ::Ice::LocalException& __ex)"; + C << sb; + C << nl << "__handleException(__ex, __cnt);"; + C << eb; + C << eb; + C << eb; + + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + if(cl->hasMetaData("ami") || p->hasMetaData("ami")) + { + string classNameAMI = "AMI_" + cl->name(); + string classScope = fixKwd(cl->scope()); + string classScopedAMI = classScope + classNameAMI; + + H << nl << "void " << name << "_async" << spar << ("const" + classScopedAMI + '_' + name + "Ptr&") + << paramsAMI << epar << ';'; + H << nl << "void " << name << "_async" << spar << ("const" + classScopedAMI + '_' + name + "Ptr&") + << paramsAMI << "const ::Ice::Context&" << epar << ';'; + + C << sp << nl << "void" << nl << "IceProxy" << scope << name << "_async" << spar + << ("const " + classScopedAMI + '_' + name + "Ptr& __cb") << paramsDeclAMI << epar; + C << sb; + C << nl << name << "_async" << spar << "__cb" << argsAMI << "__defaultContext()" << epar << ';'; + C << eb; + + C << sp << nl << "void" << nl << "IceProxy" << scope << name << "_async" << spar + << ("const " + classScopedAMI + '_' + name + "Ptr& __cb") << paramsDeclAMI << "const ::Ice::Context& __ctx" + << epar; + C << sb; + // Async requests may only be sent twoway. + C << nl << "__checkTwowayOnly(\"" << name << "\");"; + C << nl << "__cb->__invoke" << spar << "this" << argsAMI << "__ctx" << epar << ';'; + C << eb; + } +} + +Slice::Gen::DelegateVisitor::DelegateVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::DelegateVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + H << sp << nl << "namespace IceDelegate" << nl << '{'; + + return true; +} + +void +Slice::Gen::DelegateVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::DelegateVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::DelegateVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::DelegateVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) + { + return false; + } + + string name = fixKwd(p->name()); + ClassList bases = p->bases(); + + H << sp << nl << "class " << _dllExport << name << " : "; + if(bases.empty()) + { + H << "virtual public ::IceDelegate::Ice::Object"; + } + else + { + H.useCurrentPosAsIndent(); + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + H << "virtual public ::IceDelegate" << fixKwd((*q)->scoped()); + if(++q != bases.end()) + { + H << ',' << nl; + } + } + H.restoreIndent(); + } + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + return true; +} + +void +Slice::Gen::DelegateVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + H << eb << ';'; +} + +void +Slice::Gen::DelegateVisitor::visitOperation(const OperationPtr& p) +{ + string name = fixKwd(p->name()); + + TypePtr ret = p->returnType(); + string retS = returnTypeToString(ret); + + vector<string> params; + + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { +#if defined(__SUNPRO_CC) && (__SUNPRO_CC==0x550) + // + // Work around for Sun CC 5.5 bug #4853566 + // + string typeString; + if((*q)->isOutParam()) + { + typeString = outputTypeToString((*q)->type()); + } + else + { + typeString = inputTypeToString((*q)->type()); + } +#else + string typeString = (*q)->isOutParam() ? outputTypeToString((*q)->type()) : inputTypeToString((*q)->type()); +#endif + + params.push_back(typeString); + } + + params.push_back("const ::Ice::Context&"); + + H << sp << nl << "virtual " << retS << ' ' << name << spar << params << epar << " = 0;"; +} + +Slice::Gen::DelegateMVisitor::DelegateMVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::DelegateMVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + H << sp << nl << "namespace IceDelegateM" << nl << '{'; + + return true; +} + +void +Slice::Gen::DelegateMVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::DelegateMVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::DelegateMVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::DelegateMVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) + { + return false; + } + + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + ClassList bases = p->bases(); + + H << sp << nl << "class " << _dllExport << name << " : "; + H.useCurrentPosAsIndent(); + H << "virtual public ::IceDelegate" << scoped << ','; + if(bases.empty()) + { + H << nl << "virtual public ::IceDelegateM::Ice::Object"; + } + else + { + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + H << nl << "virtual public ::IceDelegateM" << fixKwd((*q)->scoped()); + if(++q != bases.end()) + { + H << ','; + } + } + } + H.restoreIndent(); + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + return true; +} + +void +Slice::Gen::DelegateMVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + H << eb << ';'; +} + +void +Slice::Gen::DelegateMVisitor::visitOperation(const OperationPtr& p) +{ + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + + TypePtr ret = p->returnType(); + string retS = returnTypeToString(ret); + + vector<string> params; + vector<string> paramsDecl; + + TypeStringList inParams; + TypeStringList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string paramName = fixKwd((*q)->name()); + TypePtr type = (*q)->type(); + bool isOutParam = (*q)->isOutParam(); + string typeString; + if(isOutParam) + { + outParams.push_back(make_pair(type, paramName)); + typeString = outputTypeToString(type); + } + else + { + inParams.push_back(make_pair(type, paramName)); + typeString = inputTypeToString(type); + } + + params.push_back(typeString); + paramsDecl.push_back(typeString + ' ' + paramName); + } + + params.push_back("const ::Ice::Context&"); + paramsDecl.push_back("const ::Ice::Context& __context"); + + H << sp << nl << "virtual " << retS << ' ' << name << spar << params << epar << ';'; + C << sp << nl << retS << nl << "IceDelegateM" << scoped << spar << paramsDecl << epar; + C << sb; + C << nl << "static const ::std::string __operation(\"" << p->name() << "\");"; + C << nl << "::IceInternal::Outgoing __out(__connection.get(), __reference.get(), __operation, " + << "static_cast< ::Ice::OperationMode>(" << p->mode() << "), __context, __compress);"; + if(!inParams.empty()) + { + C << nl << "try"; + C << sb; + C << nl << "::IceInternal::BasicStream* __os = __out.os();"; + writeMarshalCode(C, inParams, 0); + if(p->sendsClasses()) + { + C << nl << "__os->writePendingObjects();"; + } + C << eb; + C << nl << "catch(const ::Ice::LocalException& __ex)"; + C << sb; + C << nl << "__out.abort(__ex);"; + C << eb; + } + C << nl << "bool __ok = __out.invoke();"; + C << nl << "try"; + C << sb; + C << nl << "::IceInternal::BasicStream* __is = __out.is();"; + C << nl << "if(!__ok)"; + C << sb; + C << nl << "__is->throwException();"; + C << eb; + writeAllocateCode(C, TypeStringList(), ret); + writeUnmarshalCode(C, outParams, ret); + if(p->returnsClasses()) + { + C << nl << "__is->readPendingObjects();"; + } + if(ret) + { + C << nl << "return __ret;"; + } + C << eb; + + // + // Generate a catch block for each legal user exception. This is necessary + // to prevent an "impossible" user exception to be thrown if client and + // and server use different exception specifications for an operation. For + // example: + // + // Client compiled with: + // exception A {}; + // exception B {}; + // interface I { + // void op() throws A; + // }; + // + // Server compiled with: + // exception A {}; + // exception B {}; + // interface I { + // void op() throws B; // Differs from client + // }; + // + // We need the catch blocks so, if the server throws B from op(), the + // client receives UnknownUserException instead of B. + // + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); +#if defined(__SUNPRO_CC) + throws.sort(derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i) + { + string scoped = (*i)->scoped(); + C << nl << "catch(const " << fixKwd((*i)->scoped()) << "&)"; + C << sb; + C << nl << "throw;"; + C << eb; + } + C << nl << "catch(const ::Ice::UserException&)"; + C << sb; + C << nl << "throw ::Ice::UnknownUserException(__FILE__, __LINE__);"; + C << eb; + C << nl << "catch(const ::Ice::LocalException& __ex)"; + C << sb; + C << nl << "throw ::IceInternal::NonRepeatable(__ex);"; + C << eb; + C << eb; +} + +Slice::Gen::DelegateDVisitor::DelegateDVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::DelegateDVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + H << sp << nl << "namespace IceDelegateD" << nl << '{'; + + return true; +} + +void +Slice::Gen::DelegateDVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::DelegateDVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::DelegateDVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::DelegateDVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(p->isLocal()) + { + return false; + } + + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + ClassList bases = p->bases(); + + H << sp << nl << "class " << _dllExport << name << " : "; + H.useCurrentPosAsIndent(); + H << "virtual public ::IceDelegate" << scoped << ','; + if(bases.empty()) + { + H << nl << "virtual public ::IceDelegateD::Ice::Object"; + } + else + { + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + H << nl << "virtual public ::IceDelegateD" << fixKwd((*q)->scoped()); + if(++q != bases.end()) + { + H << ','; + } + } + } + H.restoreIndent(); + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + return true; +} + +void +Slice::Gen::DelegateDVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + H << eb << ';'; +} + +void +Slice::Gen::DelegateDVisitor::visitOperation(const OperationPtr& p) +{ + string name = fixKwd(p->name()); + string scoped = fixKwd(p->scoped()); + + TypePtr ret = p->returnType(); + string retS = returnTypeToString(ret); + + vector<string> params; + vector<string> paramsDecl; + vector<string> args; + + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string paramName = fixKwd((*q)->name()); + +#if defined(__SUNPRO_CC) && (__SUNPRO_CC==0x550) + // + // Work around for Sun CC 5.5 bug #4853566 + // + string typeString; + if((*q)->isOutParam()) + { + typeString = outputTypeToString((*q)->type()); + } + else + { + typeString = inputTypeToString((*q)->type()); + } +#else + string typeString = (*q)->isOutParam() ? outputTypeToString((*q)->type()) : inputTypeToString((*q)->type()); +#endif + + params.push_back(typeString); + paramsDecl.push_back(typeString + ' ' + paramName); + args.push_back(paramName); + } + + params.push_back("const ::Ice::Context&"); + paramsDecl.push_back("const ::Ice::Context& __context"); + args.push_back("__current"); + + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string thisPointer = fixKwd(cl->scoped()) + "*"; + + H << sp; + + H << nl << "virtual " << retS << ' ' << name << spar << params << epar << ';'; + bool amd = !cl->isLocal() && (cl->hasMetaData("amd") || p->hasMetaData("amd")); + if(amd) + { + C << sp << nl << retS << nl << "IceDelegateD" << scoped << spar << params << epar; + C << sb; + C << nl << "throw ::Ice::CollocationOptimizationException(__FILE__, __LINE__);"; + C << eb; + } + else + { + C << sp << nl << retS << nl << "IceDelegateD" << scoped << spar << paramsDecl << epar; + C << sb; + C << nl << "::Ice::Current __current;"; + C << nl << "__initCurrent(__current, \"" << p->name() + << "\", static_cast< ::Ice::OperationMode>(" << p->mode() << "), __context);"; + C << nl << "while(true)"; + C << sb; + C << nl << "::IceInternal::Direct __direct(__current);"; + C << nl << thisPointer << " __servant = dynamic_cast< " << thisPointer << ">(__direct.servant().get());"; + C << nl << "if(!__servant)"; + C << sb; + C << nl << "::Ice::OperationNotExistException __opEx(__FILE__, __LINE__);"; + C << nl << "__opEx.id = __current.id;"; + C << nl << "__opEx.facet = __current.facet;"; + C << nl << "__opEx.operation = __current.operation;"; + C << nl << "throw __opEx;"; + C << eb; + C << nl << "try"; + C << sb; + C << nl; + if(ret) + { + C << "return "; + } + C << "__servant->" << name << spar << args << epar << ';'; + if(!ret) + { + C << nl << "return;"; + } + C << eb; + C << nl << "catch(const ::Ice::LocalException& __ex)"; + C << sb; + C << nl << "throw ::IceInternal::NonRepeatable(__ex);"; + C << eb; + C << eb; + C << eb; + } +} + +Slice::Gen::ObjectDeclVisitor::ObjectDeclVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::ObjectDeclVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::ObjectDeclVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +void +Slice::Gen::ObjectDeclVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + string name = fixKwd(p->name()); + + H << sp << nl << "class " << name << ';'; + H << nl << _dllExport << "bool operator==(const " << name << "&, const " << name << "&);"; + H << nl << _dllExport << "bool operator!=(const " << name << "&, const " << name << "&);"; + H << nl << _dllExport << "bool operator<(const " << name << "&, const " << name << "&);"; +} + +Slice::Gen::ObjectVisitor::ObjectVisitor(Output& h, Output& c, const string& dllExport, bool stream) : + H(h), C(c), _dllExport(dllExport), _stream(stream) +{ +} + +bool +Slice::Gen::ObjectVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasClassDefs()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::ObjectVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp; + H << nl << '}'; +} + +bool +Slice::Gen::ObjectVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string name = fixKwd(p->name()); + ClassList bases = p->bases(); + + H << sp; + H << nl << "class " << _dllExport << name << " : "; + H.useCurrentPosAsIndent(); + if(bases.empty()) + { + if(p->isLocal()) + { + H << "virtual public ::Ice::LocalObject"; + } + else + { + H << "virtual public ::Ice::Object"; + } + } + else + { + ClassList::const_iterator q = bases.begin(); + while(q != bases.end()) + { + H << "virtual public " << fixKwd((*q)->scoped()); + if(++q != bases.end()) + { + H << ',' << nl; + } + } + } + H.restoreIndent(); + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + if(!p->isAbstract() && !p->isLocal()) + { + H << sp << nl << "void __copyMembers(" << fixKwd(p->scoped() + "Ptr") + ") const;"; + + C << sp; + C << nl << "void "; + C << nl << fixKwd(p->scoped()).substr(2) << "::__copyMembers(" << fixKwd(p->scoped() + "Ptr") << " __to) const"; + C << sb; + string winUpcall; + string unixUpcall; + if(!bases.empty() && !bases.front()->isInterface()) + { + winUpcall = fixKwd(bases.front()->name()) + "::__copyMembers(__to);"; + unixUpcall = fixKwd(bases.front()->scoped()) + "::__copyMembers(__to);"; + } + else + { + winUpcall = "Object::__copyMembers(__to);"; + unixUpcall = "::Ice::Object::__copyMembers(__to);"; + } + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << winUpcall; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << unixUpcall; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + DataMemberList dataMembers = p->dataMembers(); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + C << nl << "__to->" << fixKwd((*q)->name()) << " = " << fixKwd((*q)->name()) << ';'; + } + C << eb; + + H << nl << "virtual ::Ice::ObjectPtr ice_clone() const;"; + + C << sp; + C << nl << "::Ice::ObjectPtr"; + C << nl << fixKwd(p->scoped()).substr(2) << "::ice_clone() const"; + C << sb; + C << nl << fixKwd(p->scope()) << p->name() << "Ptr __p = new " << fixKwd(p->scoped()) << ';'; + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << fixKwd(name) + "::__copyMembers(__p);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << fixKwd(p->scoped()) + "::__copyMembers(__p);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << nl << "return __p;"; + C << eb; + } + + if(!p->isLocal()) + { + ClassList allBases = p->allBases(); + StringList ids; +#if defined(__IBMCPP__) && defined(NDEBUG) +// +// VisualAge C++ 6.0 does not see that ClassDef is a Contained, +// when inlining is on. The code below issues a warning: better +// than an error! +// + transform(allBases.begin(), allBases.end(), back_inserter(ids), ::IceUtil::constMemFun<string,ClassDef>(&Contained::scoped)); +#else + transform(allBases.begin(), allBases.end(), back_inserter(ids), ::IceUtil::constMemFun(&Contained::scoped)); +#endif + 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(), p->scoped()); + assert(scopedIter != ids.end()); + StringList::difference_type scopedPos = ice_distance(firstIter, scopedIter); + + StringList::const_iterator q; + + H << sp; + H << nl << "virtual bool ice_isA" + << "(const ::std::string&, const ::Ice::Current& = ::Ice::Current()) const;"; + H << nl << "virtual ::std::vector< ::std::string> ice_ids" + << "(const ::Ice::Current& = ::Ice::Current()) const;"; + H << nl << "virtual const ::std::string& ice_id(const ::Ice::Current& = ::Ice::Current()) const;"; + H << nl << "static const ::std::string& ice_staticId();"; + + string flatName = p->flattenedScope() + p->name() + "_ids"; + + C << sp; + C << nl << "static const ::std::string " << flatName << '[' << ids.size() << "] ="; + C << sb; + q = ids.begin(); + while(q != ids.end()) + { + C << nl << '"' << *q << '"'; + if(++q != ids.end()) + { + C << ','; + } + } + C << eb << ';'; + + C << sp; + C << nl << "bool" << nl << fixKwd(p->scoped()).substr(2) + << "::ice_isA(const ::std::string& _s, const ::Ice::Current&) const"; + C << sb; + C << nl << "return ::std::binary_search(" << flatName << ", " << flatName << " + " << ids.size() << ", _s);"; + C << eb; + + C << sp; + C << nl << "::std::vector< ::std::string>" << nl << fixKwd(p->scoped()).substr(2) + << "::ice_ids(const ::Ice::Current&) const"; + C << sb; + C << nl << "return ::std::vector< ::std::string>(&" << flatName << "[0], &" << flatName + << '[' << ids.size() << "]);"; + C << eb; + + C << sp; + C << nl << "const ::std::string&" << nl << fixKwd(p->scoped()).substr(2) + << "::ice_id(const ::Ice::Current&) const"; + C << sb; + C << nl << "return " << flatName << '[' << scopedPos << "];"; + C << eb; + + C << sp; + C << nl << "const ::std::string&" << nl << fixKwd(p->scoped()).substr(2) << "::ice_staticId()"; + C << sb; + C << nl << "return " << flatName << '[' << scopedPos << "];"; + C << eb; + + emitGCFunctions(p); + } + + return true; +} + +void +Slice::Gen::ObjectVisitor::visitClassDefEnd(const ClassDefPtr& p) +{ + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + if(!p->isLocal()) + { + ClassList bases = p->bases(); + ClassDefPtr base; + if(!bases.empty() && !bases.front()->isInterface()) + { + base = bases.front(); + } + + OperationList allOps = p->allOperations(); + if(!allOps.empty()) + { + StringList allOpNames; +#if defined(__IBMCPP__) && defined(NDEBUG) +// +// See comment for transform above +// + transform(allOps.begin(), allOps.end(), back_inserter(allOpNames), + ::IceUtil::constMemFun<string,Operation>(&Contained::name)); +#else + transform(allOps.begin(), allOps.end(), back_inserter(allOpNames), + ::IceUtil::constMemFun(&Contained::name)); +#endif + allOpNames.push_back("ice_id"); + allOpNames.push_back("ice_ids"); + allOpNames.push_back("ice_isA"); + allOpNames.push_back("ice_ping"); + allOpNames.sort(); + allOpNames.unique(); + + StringList::const_iterator q; + + H << sp; + H << nl + << "virtual ::IceInternal::DispatchStatus __dispatch(::IceInternal::Incoming&, const ::Ice::Current&);"; + + string flatName = p->flattenedScope() + p->name() + "_all"; + C << sp; + C << nl << "static ::std::string " << flatName << "[] ="; + C << sb; + q = allOpNames.begin(); + while(q != allOpNames.end()) + { + C << nl << '"' << *q << '"'; + if(++q != allOpNames.end()) + { + C << ','; + } + } + C << eb << ';'; + C << sp; + C << nl << "::IceInternal::DispatchStatus" << nl << scoped.substr(2) + << "::__dispatch(::IceInternal::Incoming& in, const ::Ice::Current& current)"; + C << sb; + + C << nl << "::std::pair< ::std::string*, ::std::string*> r = " + << "::std::equal_range(" << flatName << ", " << flatName << " + " << allOpNames.size() + << ", current.operation);"; + C << nl << "if(r.first == r.second)"; + C << sb; + C << nl << "return ::IceInternal::DispatchOperationNotExist;"; + C << eb; + C << sp; + C << nl << "switch(r.first - " << flatName << ')'; + C << sb; + int i = 0; + for(q = allOpNames.begin(); q != allOpNames.end(); ++q) + { + C << nl << "case " << i++ << ':'; + C << sb; + C << nl << "return ___" << *q << "(in, current);"; + C << eb; + } + C << eb; + C << sp; + C << nl << "assert(false);"; + C << nl << "return ::IceInternal::DispatchOperationNotExist;"; + C << eb; + } + + H << sp; + H << nl << "virtual void __write(::IceInternal::BasicStream*) const;"; + H << nl << "virtual void __read(::IceInternal::BasicStream*, bool);"; + H << nl << "virtual void __write(const ::Ice::OutputStreamPtr&) const;"; + H << nl << "virtual void __read(const ::Ice::InputStreamPtr&, bool);"; + + TypeStringList memberList; + DataMemberList dataMembers = p->dataMembers(); + for(DataMemberList::const_iterator q = dataMembers.begin(); q != dataMembers.end(); ++q) + { + memberList.push_back(make_pair((*q)->type(), (*q)->name())); + } + C << sp; + C << nl << "void" << nl << scoped.substr(2) + << "::__write(::IceInternal::BasicStream* __os) const"; + C << sb; + C << nl << "__os->writeTypeId(ice_staticId());"; + C << nl << "__os->startWriteSlice();"; + writeMarshalCode(C, memberList, 0); + C << nl << "__os->endWriteSlice();"; + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << (base ? fixKwd(base->name()) : "Object") << "::__write(__os);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << (base ? fixKwd(base->scoped()) : "::Ice::Object") << "::__write(__os);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << eb; + C << sp; + C << nl << "void" << nl << scoped.substr(2) << "::__read(::IceInternal::BasicStream* __is, bool __rid)"; + C << sb; + C << nl << "if(__rid)"; + C << sb; + C << nl << "::std::string myId;"; + C << nl << "__is->readTypeId(myId);"; + C << eb; + C << nl << "__is->startReadSlice();"; + writeUnmarshalCode(C, memberList, 0); + C << nl << "__is->endReadSlice();"; + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << (base ? fixKwd(base->name()) : "Object") << "::__read(__is, true);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << (base ? fixKwd(base->scoped()) : "::Ice::Object") << "::__read(__is, true);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << eb; + + if(_stream) + { + C << sp; + C << nl << "void" << nl << scoped.substr(2) << "::__write(const ::Ice::OutputStreamPtr& __out) const"; + C << sb; + C << nl << "__out->writeTypeId(ice_staticId());"; + C << nl << "__out->startSlice();"; + writeStreamMarshalCode(C, memberList, 0); + C << nl << "__out->endSlice();"; + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << (base ? fixKwd(base->name()) : "Object") << "::__write(__out);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << (base ? fixKwd(base->scoped()) : "::Ice::Object") << "::__write(__out);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << eb; + C << sp; + C << nl << "void" << nl << scoped.substr(2) << "::__read(const ::Ice::InputStreamPtr& __in, bool __rid)"; + C << sb; + C << nl << "if(__rid)"; + C << sb; + C << nl << "__in->readTypeId();"; + C << eb; + C << nl << "__in->startSlice();"; + writeStreamUnmarshalCode(C, memberList, 0); + C << nl << "__in->endSlice();"; + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (_MSC_VER < 1300) // VC++ 6 compiler bug"; // COMPILERBUG + C.restoreIndent(); + C << nl << (base ? fixKwd(base->name()) : "Object") << "::__read(__in, true);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << (base ? fixKwd(base->scoped()) : "::Ice::Object") << "::__read(__in, true);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << eb; + } + else + { + // + // Emit placeholder functions to catch errors. + // + C << sp; + C << nl << "void" << nl << scoped.substr(2) << "::__write(const ::Ice::OutputStreamPtr&) const"; + C << sb; + C << nl << "Ice::MarshalException ex(__FILE__, __LINE__);"; + C << nl << "ex.reason = \"type " << scoped.substr(2) << " was not generated with stream support\";"; + C << nl << "throw ex;"; + C << eb; + C << sp; + C << nl << "void" << nl << scoped.substr(2) << "::__read(const ::Ice::InputStreamPtr&, bool)"; + C << sb; + C << nl << "Ice::MarshalException ex(__FILE__, __LINE__);"; + C << nl << "ex.reason = \"type " << scoped.substr(2) << " was not generated with stream support\";"; + C << nl << "throw ex;"; + C << eb; + } + + if(!p->isAbstract()) + { + H << sp << nl << "static const ::Ice::ObjectFactoryPtr& ice_factory();"; + + string factoryName = "__F" + p->flattenedScope() + p->name(); + C << sp; + C << nl << "class " << factoryName << " : public ::Ice::ObjectFactory"; + C << sb; + C.dec(); + C << nl << "public:"; + C.inc(); + C << sp << nl << "virtual ::Ice::ObjectPtr" << nl << "create(const ::std::string& type)"; + C << sb; + C << nl << "assert(type == " << scoped << "::ice_staticId());"; + C << nl << "return new " << scoped << ';'; + C << eb; + C << sp << nl << "virtual void" << nl << "destroy()"; + C << sb; + C << eb; + C << eb << ';'; + + string flatName = factoryName + "_Ptr"; + C << sp; + C << nl << "static ::Ice::ObjectFactoryPtr " << flatName << " = new " << factoryName << ';'; + + C << sp << nl << "const ::Ice::ObjectFactoryPtr&" << nl << scoped.substr(2) << "::ice_factory()"; + C << sb; + C << nl << "return " << flatName << ';'; + C << eb; + + C << sp; + C << nl << "class " << factoryName << "__Init"; + C << sb; + C.dec(); + C << nl << "public:"; + C.inc(); + C << sp << nl << factoryName << "__Init()"; + C << sb; + C << nl << "::Ice::factoryTable->addObjectFactory(" << scoped << "::ice_staticId(), " + << scoped << "::ice_factory());"; + C << eb; + C << sp << nl << "~" << factoryName << "__Init()"; + C << sb; + C << nl << "::Ice::factoryTable->removeObjectFactory(" << scoped << "::ice_staticId());"; + C << eb; + C << eb << ';'; + + C << sp; + C << nl << "static " << factoryName << "__Init " << factoryName << "__i;"; + C << sp << nl << "#ifdef __APPLE__"; + std::string initfuncname = "__F" + p->flattenedScope() + p->name() + "__initializer"; + C << nl << "extern \"C\" { void " << initfuncname << "() {} }"; + C << nl << "#endif"; + } + } + + H << eb << ';'; + + if(!p->isAbstract() && !p->isLocal()) + { + H << sp << nl << "static " << scoped << " __" << p->name() << "_init;"; + } + + if(p->isLocal()) + { + C << sp; + C << nl << "bool" << nl << scope.substr(2) << "operator==(const " << scoped + << "& l, const " << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::Ice::LocalObject&>(l) == static_cast<const ::Ice::LocalObject&>(r);"; + C << eb; + C << sp; + C << nl << "bool" << nl << scope.substr(2) << "operator!=(const " << scoped + << "& l, const " << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::Ice::LocalObject&>(l) != static_cast<const ::Ice::LocalObject&>(r);"; + C << eb; + C << sp; + C << nl << "bool" << nl << scope.substr(2) << "operator<(const " << scoped + << "& l, const " << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::Ice::LocalObject&>(l) < static_cast<const ::Ice::LocalObject&>(r);"; + C << eb; + } + else + { + string name = p->name(); + + H << sp << nl << "void " << _dllExport << "__patch__" << name << "Ptr(void*, ::Ice::ObjectPtr&);"; + + C << sp << nl << "void " << _dllExport; + C << nl << scope.substr(2) << "__patch__" << name << "Ptr(void* __addr, ::Ice::ObjectPtr& v)"; + C << sb; + C << nl << scope << name << "Ptr* p = static_cast< " << scope << name << "Ptr*>(__addr);"; + C << nl << "assert(p);"; + C << nl << "*p = " << scope << name << "Ptr::dynamicCast(v);"; + C << nl << "if(v && !*p)"; + C << sb; + C << nl << "::Ice::NoObjectFactoryException e(__FILE__, __LINE__);"; + C << nl << "e.type = " << scope << fixKwd(name) << "::ice_staticId();"; + C << nl << "throw e;"; + C << eb; + C << eb; + + C << sp; + C << nl << "bool" << nl << scope.substr(2) << "operator==(const " << scoped + << "& l, const " << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::Ice::Object&>(l) == static_cast<const ::Ice::Object&>(r);"; + C << eb; + C << sp; + C << nl << "bool" << nl << scope.substr(2) << "operator!=(const " << scoped + << "& l, const " << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::Ice::Object&>(l) != static_cast<const ::Ice::Object&>(r);"; + C << eb; + C << sp; + C << nl << "bool" << nl << scope.substr(2) << "operator<(const " << scoped + << "& l, const " << scoped << "& r)"; + C << sb; + C << nl << "return static_cast<const ::Ice::Object&>(l) < static_cast<const ::Ice::Object&>(r);"; + C << eb; + } +} + +bool +Slice::Gen::ObjectVisitor::visitExceptionStart(const ExceptionPtr&) +{ + return false; +} + +bool +Slice::Gen::ObjectVisitor::visitStructStart(const StructPtr&) +{ + return false; +} + +void +Slice::Gen::ObjectVisitor::visitOperation(const OperationPtr& p) +{ + string name = p->name(); + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + TypePtr ret = p->returnType(); + string retS = returnTypeToString(ret); + + string params = "("; + string paramsDecl = "("; + string args = "("; + + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + string classNameAMD = "AMD_" + cl->name(); + string classScope = fixKwd(cl->scope()); + string classScopedAMD = classScope + classNameAMD; + + string paramsAMD = "(const " + classScopedAMD + '_' + name + "Ptr&, "; + string paramsDeclAMD = "(const " + classScopedAMD + '_' + name + "Ptr& __cb, "; + string argsAMD = "(__cb, "; + + TypeStringList inParams; + TypeStringList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string paramName = fixKwd((*q)->name()); + TypePtr type = (*q)->type(); + bool isOutParam = (*q)->isOutParam(); + string typeString; + if(isOutParam) + { + outParams.push_back(make_pair(type, paramName)); + typeString = outputTypeToString(type); + } + else + { + inParams.push_back(make_pair(type, paramName)); + typeString = inputTypeToString((*q)->type()); + } + + if(q != paramList.begin()) + { + params += ", "; + paramsDecl += ", "; + args += ", "; + } + + params += typeString; + paramsDecl += typeString; + paramsDecl += ' '; + paramsDecl += paramName; + args += paramName; + + if(!isOutParam) + { + paramsAMD += typeString; + paramsAMD += ", "; + paramsDeclAMD += typeString; + paramsDeclAMD += ' '; + paramsDeclAMD += paramName; + paramsDeclAMD += ", "; + argsAMD += paramName; + argsAMD += ", "; + } + } + + if(!cl->isLocal()) + { + if(!paramList.empty()) + { + params += ", "; + paramsDecl += ", "; + args += ", "; + } + + params += "const ::Ice::Current& = ::Ice::Current())"; + paramsDecl += "const ::Ice::Current& __current)"; + args += "__current)"; + } + else + { + params += ')'; + paramsDecl += ')'; + args += ')'; + } + + paramsAMD += "const ::Ice::Current& = ::Ice::Current())"; + paramsDeclAMD += "const ::Ice::Current& __current)"; + argsAMD += "__current)"; + + bool nonmutating = p->mode() == Operation::Nonmutating; + bool amd = !cl->isLocal() && (cl->hasMetaData("amd") || p->hasMetaData("amd")); + + H << sp; + if(!amd) + { + H << nl << "virtual " << retS << ' ' << fixKwd(name) << params + << (nonmutating ? " const" : "") << " = 0;"; + } + else + { + H << nl << "virtual void " << name << "_async" << paramsAMD + << (nonmutating ? " const" : "") << " = 0;"; + } + + if(!cl->isLocal()) + { + H << nl << "::IceInternal::DispatchStatus ___" << name + << "(::IceInternal::Incoming&, const ::Ice::Current&)" << (nonmutating ? " const" : "") << ';'; + + C << sp; + C << nl << "::IceInternal::DispatchStatus" << nl << scope.substr(2) << "___" << name + << "(::IceInternal::Incoming& __in, const ::Ice::Current& __current)" << (nonmutating ? " const" : ""); + C << sb; + if(!amd) + { + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); + + // + // 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. + // + +#if defined(__SUNPRO_CC) + throws.sort(derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + + if(!inParams.empty()) + { + C << nl << "::IceInternal::BasicStream* __is = __in.is();"; + } + if(ret || !outParams.empty() || !throws.empty()) + { + C << nl << "::IceInternal::BasicStream* __os = __in.os();"; + } + writeAllocateCode(C, inParams, 0); + writeUnmarshalCode(C, inParams, 0); + if(p->sendsClasses()) + { + C << nl << "__is->readPendingObjects();"; + } + writeAllocateCode(C, outParams, 0); + if(!throws.empty()) + { + C << nl << "try"; + C << sb; + } + C << nl; + if(ret) + { + C << retS << " __ret = "; + } + C << fixKwd(name) << args << ';'; + writeMarshalCode(C, outParams, ret); + if(p->returnsClasses()) + { + C << nl << "__os->writePendingObjects();"; + } + if(!throws.empty()) + { + C << eb; + ExceptionList::const_iterator r; + for(r = throws.begin(); r != throws.end(); ++r) + { + C << nl << "catch(const " << fixKwd((*r)->scoped()) << "& __ex)"; + C << sb; + C << nl << "__os->write(__ex);"; + C << nl << "return ::IceInternal::DispatchUserException;"; + C << eb; + } + } + C << nl << "return ::IceInternal::DispatchOK;"; + } + else + { + if(!inParams.empty()) + { + C << nl << "::IceInternal::BasicStream* __is = __in.is();"; + } + writeAllocateCode(C, inParams, 0); + writeUnmarshalCode(C, inParams, 0); + if(p->sendsClasses()) + { + C << nl << "__is->readPendingObjects();"; + } + C << nl << classScopedAMD << '_' << name << "Ptr __cb = new IceAsync" << classScopedAMD << '_' << name + << "(__in);"; + C << nl << "try"; + C << sb; + C << nl << name << "_async" << argsAMD << ';'; + C << eb; + C << nl << "catch(const ::Ice::Exception& __ex)"; + C << sb; + C << nl << "__cb->ice_exception(__ex);"; + C << eb; + C << nl << "catch(const ::std::exception& __ex)"; + C << sb; + C << nl << "__cb->ice_exception(__ex);"; + C << eb; + C << nl << "catch(...)"; + C << sb; + C << nl << "__cb->ice_exception();"; + C << eb; + C << nl << "return ::IceInternal::DispatchAsync;"; + } + C << eb; + } +} + +void +Slice::Gen::ObjectVisitor::visitDataMember(const DataMemberPtr& p) +{ + string name = fixKwd(p->name()); + string s = typeToString(p->type()); + H << sp; + H << nl << s << ' ' << name << ';'; +} + +void +Slice::Gen::ObjectVisitor::emitGCFunctions(const ClassDefPtr& p) +{ + string scoped = fixKwd(p->scoped()); + ClassList bases = p->bases(); + DataMemberList dataMembers = p->dataMembers(); + + // + // A class can potentially be part of a cycle if it (recursively) contains class + // members. If so, we override __incRef() and __decRef() and, hence, consider instances + // of the class as candidates for collection by the garbage collector. + // We override __incRef() and __decRef() only once, in the basemost potentially cyclic class + // in an inheritance hierarchy. + // + bool hasBaseClass = !bases.empty() && !bases.front()->isInterface(); + bool canBeCyclic = p->canBeCyclic(); + bool override = canBeCyclic && (!hasBaseClass || !bases.front()->canBeCyclic()); + + if(override) + { + H << nl << "virtual void __incRef();"; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__incRef()"; + C << sb; + C << nl << "IceUtil::gcRecMutex._m->lock();"; + C << nl << "assert(_ref >= 0);"; + C << nl << "if(_ref == 0)"; + C << sb; + C.zeroIndent(); + C << nl << "#ifdef NDEBUG // To avoid annoying warnings about variables that are not used..."; + C.restoreIndent(); + C << nl << "IceUtil::gcObjects.insert(this);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << "std::pair<IceUtil::GCObjectSet::iterator, bool> rc = IceUtil::gcObjects.insert(this);"; + C << nl << "assert(rc.second);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << eb; + C << nl << "++_ref;"; + C << nl << "IceUtil::gcRecMutex._m->unlock();"; + C << eb; + + H << nl << "virtual void __decRef();"; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__decRef()"; + C << sb; + C << nl << "IceUtil::gcRecMutex._m->lock();"; + C << nl << "bool doDelete = false;"; + C << nl << "assert(_ref > 0);"; + C << nl << "if(--_ref == 0)"; + C << sb; + C << nl << "doDelete = !_noDelete;"; + C << nl << "_noDelete = true;"; + C.zeroIndent(); + C << nl << "#ifdef NDEBUG // To avoid annoying warnings about variables that are not used..."; + C.restoreIndent(); + C << nl << "IceUtil::gcObjects.erase(this);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << "IceUtil::GCObjectSet::size_type num = IceUtil::gcObjects.erase(this);"; + C << nl << "assert(num == 1);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + C << eb; + C << nl << "IceUtil::gcRecMutex._m->unlock();"; + C << nl << "if(doDelete)"; + C << sb; + C << nl << "delete this;"; + C << eb; + C << eb; + } + + // + // __gcReachable() and __gcClear() are overridden by the basemost class that + // can be cyclic, plus all classes derived from that class. + // + if(canBeCyclic) + { + H << nl << "virtual void __gcReachable(::IceUtil::GCObjectMultiSet&) const;"; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__gcReachable(::IceUtil::GCObjectMultiSet& _c) const"; + C << sb; + + string vc6Prefix; + string otherPrefix; + + bool hasCyclicBase = hasBaseClass && bases.front()->canBeCyclic(); + if(hasCyclicBase) + { + vc6Prefix = bases.front()->name(); + otherPrefix = bases.front()->scoped(); + + // + // Up-call to the base's __gcReachable() member function. + // + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (MSC_VER < 1300) // VC++ 6 compiler bug"; + C.restoreIndent(); + C << nl << vc6Prefix << "::__gcReachable(_c);"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << otherPrefix << "::__gcReachable(_c);"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + } + for(DataMemberList::const_iterator i = dataMembers.begin(); i != dataMembers.end(); ++i) + { + if((*i)->type()->usesClasses()) + { + emitGCInsertCode((*i)->type(), fixKwd((*i)->name()), "", 0); + } + } + C << eb; + + H << nl << "virtual void __gcClear();"; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__gcClear()"; + C << sb; + if(hasCyclicBase) + { + // + // Up-call to the base's __gcClear() member function. + // + C.zeroIndent(); + C << nl << "#if defined(_MSC_VER) && (MSC_VER < 1300) // VC++ 6 compiler bug"; + C.restoreIndent(); + C << nl << vc6Prefix<< "::__gcClear();"; + C.zeroIndent(); + C << nl << "#else"; + C.restoreIndent(); + C << nl << otherPrefix << "::__gcClear();"; + C.zeroIndent(); + C << nl << "#endif"; + C.restoreIndent(); + } + for(DataMemberList::const_iterator j = dataMembers.begin(); j != dataMembers.end(); ++j) + { + if((*j)->type()->usesClasses()) + { + emitGCClearCode((*j)->type(), fixKwd((*j)->name()), "", 0); + } + } + C << eb; + } +} + +void +Slice::Gen::ObjectVisitor::emitGCInsertCode(const TypePtr& p, const string& prefix, const string& name, int level) +{ + if((BuiltinPtr::dynamicCast(p) && BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindObject) + || ClassDeclPtr::dynamicCast(p)) + { + C << nl << "__addObject(_c, " << prefix << name << ".get());"; + } + else if(StructPtr s = StructPtr::dynamicCast(p)) + { + DataMemberList dml = s->dataMembers(); + for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) + { + if((*i)->type()->usesClasses()) + { + emitGCInsertCode((*i)->type(), prefix + name + ".", fixKwd((*i)->name()), ++level); + } + } + } + else if(DictionaryPtr d = DictionaryPtr::dynamicCast(p)) + { + string scoped = fixKwd(d->scoped()); + stringstream tmp; + tmp << "_i" << level; + string iterName = tmp.str(); + C << sb; + C << nl << "for(" << scoped << "::const_iterator " << iterName << " = " << prefix + name + << ".begin(); " << iterName << " != " << prefix + name << ".end(); ++" << iterName << ")"; + C << sb; + emitGCInsertCode(d->valueType(), "", string("(*") + iterName + ").second", ++level); + C << eb; + C << eb; + } + else if(SequencePtr s = SequencePtr::dynamicCast(p)) + { + string scoped = fixKwd(s->scoped()); + stringstream tmp; + tmp << "_i" << level; + string iterName = tmp.str(); + C << sb; + C << nl << "for(" << scoped << "::const_iterator " << iterName << " = " << prefix + name + << ".begin(); " << iterName << " != " << prefix + name << ".end(); ++" << iterName << ")"; + C << sb; + emitGCInsertCode(s->type(), string("(*") + iterName + ")", "", ++level); + C << eb; + C << eb; + } +} + +void +Slice::Gen::ObjectVisitor::emitGCClearCode(const TypePtr& p, const string& prefix, const string& name, int level) +{ + if((BuiltinPtr::dynamicCast(p) && BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindObject) + || ClassDeclPtr::dynamicCast(p)) + { + C << nl << "if(" << prefix << name << ")"; + C << sb; + C << nl << prefix << name << "->__decRefUnsafe();"; + C << nl << prefix << name << ".__clearHandleUnsafe();"; + C << eb; + } + else if(StructPtr s = StructPtr::dynamicCast(p)) + { + DataMemberList dml = s->dataMembers(); + for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) + { + if((*i)->type()->usesClasses()) + { + emitGCClearCode((*i)->type(), prefix + name + ".", fixKwd((*i)->name()), ++level); + } + } + } + else if(DictionaryPtr d = DictionaryPtr::dynamicCast(p)) + { + string scoped = fixKwd(d->scoped()); + stringstream tmp; + tmp << "_i" << level; + string iterName = tmp.str(); + C << sb; + C << nl << "for(" << scoped << "::iterator " << iterName << " = " << prefix + name + << ".begin(); " << iterName << " != " << prefix + name << ".end(); ++" << iterName << ")"; + C << sb; + emitGCClearCode(d->valueType(), "", string("(*") + iterName + ").second", ++level); + C << eb; + C << eb; + } + else if(SequencePtr s = SequencePtr::dynamicCast(p)) + { + string scoped = fixKwd(s->scoped()); + stringstream tmp; + tmp << "_i" << level; + string iterName = tmp.str(); + C << sb; + C << nl << "for(" << scoped << "::iterator " << iterName << " = " << prefix + name + << ".begin(); " << iterName << " != " << prefix + name << ".end(); ++" << iterName << ")"; + C << sb; + emitGCClearCode(s->type(), "", string("(*") + iterName + ")", ++level); + C << eb; + C << eb;; + } +} + +Slice::Gen::IceInternalVisitor::IceInternalVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::IceInternalVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasClassDecls()) + { + return false; + } + + H << sp; + H << nl << "namespace IceInternal" << nl << '{'; + + return true; +} + +void +Slice::Gen::IceInternalVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp; + H << nl << '}'; +} + +void +Slice::Gen::IceInternalVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + string scoped = fixKwd(p->scoped()); + + H << sp; + H << nl << _dllExport << "void incRef(" << scoped << "*);"; + H << nl << _dllExport << "void decRef(" << scoped << "*);"; + if(!p->isLocal()) + { + H << sp; + H << nl << _dllExport << "void incRef(::IceProxy" << scoped << "*);"; + H << nl << _dllExport << "void decRef(::IceProxy" << scoped << "*);"; + } +} + +bool +Slice::Gen::IceInternalVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + string scoped = fixKwd(p->scoped()); + + C << sp; + C << nl << "void" << nl << "IceInternal::incRef(" << scoped << "* p)"; + C << sb; + C << nl << "p->__incRef();"; + C << eb; + + C << sp; + C << nl << "void" << nl << "IceInternal::decRef(" << scoped << "* p)"; + C << sb; + C << nl << "p->__decRef();"; + C << eb; + + if(!p->isLocal()) + { + C << sp; + C << nl << "void" << nl << "IceInternal::incRef(::IceProxy" << scoped << "* p)"; + C << sb; + C << nl << "p->__incRef();"; + C << eb; + + C << sp; + C << nl << "void" << nl << "IceInternal::decRef(::IceProxy" << scoped << "* p)"; + C << sb; + C << nl << "p->__decRef();"; + C << eb; + } + + return true; +} + +Slice::Gen::HandleVisitor::HandleVisitor(Output& h, Output& c, const string& dllExport, bool stream) : + H(h), C(c), _dllExport(dllExport), _stream(stream) +{ +} + +bool +Slice::Gen::HandleVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasClassDecls()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp; + H << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::HandleVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp; + H << nl << '}'; +} + +void +Slice::Gen::HandleVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + string name = p->name(); + string scoped = fixKwd(p->scoped()); + + H << sp; + H << nl << "typedef ::IceInternal::Handle< " << scoped << "> " << name << "Ptr;"; + if(!p->isLocal()) + { + H << nl << "typedef ::IceInternal::ProxyHandle< ::IceProxy" << scoped << "> " << name << "Prx;"; + + H << sp; + H << nl << _dllExport << "void __write(::IceInternal::BasicStream*, const " << name << "Prx&);"; + H << nl << _dllExport << "void __read(::IceInternal::BasicStream*, " << name << "Prx&);"; + H << nl << _dllExport << "void __write(::IceInternal::BasicStream*, const " << name << "Ptr&);"; + H << nl << _dllExport << "void __patch__" << name << "Ptr(void*, ::Ice::ObjectPtr&);"; + if(_stream) + { + H << sp; + H << nl << _dllExport << "void ice_write" << name << "Prx(const ::Ice::OutputStreamPtr&, const " << name + << "Prx&);"; + H << nl << _dllExport << "void ice_read" << name << "Prx(const ::Ice::InputStreamPtr&, " << name + << "Prx&);"; + + H << nl << _dllExport << "void ice_write" << name << "(const ::Ice::OutputStreamPtr&, const " + << name << "Ptr&);"; + H << nl << _dllExport << "void ice_read" << name << "(const ::Ice::InputStreamPtr&, " << name << "Ptr&);"; + } + } +} + +bool +Slice::Gen::HandleVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(!p->isLocal()) + { + string name = p->name(); + string scoped = fixKwd(p->scoped()); + string scope = fixKwd(p->scope()); + + string factory; + string type; + if(!p->isAbstract()) + { + type = scoped + "::ice_staticId()"; + factory = scoped + "::ice_factory()"; + } + else + { + type = "\"\""; + factory = "0"; + } + + C << sp; + C << nl << "void" << nl << scope.substr(2) << "__write(::IceInternal::BasicStream* __os, const " + << scope << name << "Prx& v)"; + C << sb; + C << nl << "__os->write(::Ice::ObjectPrx(v));"; + C << eb; + + C << sp; + C << nl << "void" << nl << scope.substr(2) << "__read(::IceInternal::BasicStream* __is, " + << scope << name << "Prx& v)"; + C << sb; + C << nl << "::Ice::ObjectPrx proxy;"; + C << nl << "__is->read(proxy);"; + C << nl << "if(!proxy)"; + C << sb; + C << nl << "v = 0;"; + C << eb; + C << nl << "else"; + C << sb; + C << nl << "v = new ::IceProxy" << scoped << ';'; + C << nl << "v->__copyFrom(proxy);"; + C << eb; + C << eb; + + C << sp; + C << nl << "void" << nl << scope.substr(2) << "__write(::IceInternal::BasicStream* __os, const " + << scope << name << "Ptr& v)"; + C << sb; + C << nl << "__os->write(::Ice::ObjectPtr(v));"; + C << eb; + + if(_stream) + { + C << sp; + C << nl << "void" << nl << scope.substr(2) << "ice_write" << name + << "Prx(const ::Ice::OutputStreamPtr& __out, const " << scope << name << "Prx& v)"; + C << sb; + C << nl << "__out->writeProxy(v);"; + C << eb; + + C << sp; + C << nl << "void" << nl << scope.substr(2) << "ice_read" << name + << "Prx(const ::Ice::InputStreamPtr& __in, " << scope << name << "Prx& v)"; + C << sb; + C << nl << "::Ice::ObjectPrx proxy = __in->readProxy();"; + C << nl << "if(!proxy)"; + C << sb; + C << nl << "v = 0;"; + C << eb; + C << nl << "else"; + C << sb; + C << nl << "v = new ::IceProxy" << scoped << ';'; + C << nl << "v->__copyFrom(proxy);"; + C << eb; + C << eb; + + C << sp; + C << nl << "void" << nl << scope.substr(2) << "ice_write" << name + << "(const ::Ice::OutputStreamPtr& __out, const " << scope << name << "Ptr& v)"; + C << sb; + C << nl << "__out->writeObject(v);"; + C << eb; + + C << sp; + C << nl << "void" << nl << scope.substr(2) << "ice_read" << name << "(const ::Ice::InputStreamPtr& __in, " + << scoped << "Ptr& __v)"; + C << sb; + C << nl << "::Ice::ReadObjectCallbackPtr __cb = new ::Ice::ReadObjectCallbackI(" << scope << "__patch__" + << name << "Ptr, &__v);"; + C << nl << "__in->readObject(__cb);"; + C << eb; + } + } + + return true; +} + +Slice::Gen::ImplVisitor::ImplVisitor(Output& h, Output& c, + const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +void +Slice::Gen::ImplVisitor::writeDecl(Output& out, const string& name, const TypePtr& type) +{ + out << nl << typeToString(type) << ' ' << name; + + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + out << " = false"; + break; + } + case Builtin::KindByte: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + { + out << " = 0"; + break; + } + case Builtin::KindFloat: + case Builtin::KindDouble: + { + out << " = 0.0"; + break; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + break; + } + } + } + + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + EnumeratorList enumerators = en->getEnumerators(); + out << " = " << fixKwd(en->scope()) << fixKwd(enumerators.front()->name()); + } + + out << ';'; +} + +void +Slice::Gen::ImplVisitor::writeReturn(Output& out, const TypePtr& type) +{ + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if(builtin) + { + switch(builtin->kind()) + { + case Builtin::KindBool: + { + out << nl << "return false;"; + break; + } + case Builtin::KindByte: + case Builtin::KindShort: + case Builtin::KindInt: + case Builtin::KindLong: + { + out << nl << "return 0;"; + break; + } + case Builtin::KindFloat: + case Builtin::KindDouble: + { + out << nl << "return 0.0;"; + break; + } + case Builtin::KindString: + { + out << nl << "return ::std::string();"; + break; + } + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + out << nl << "return 0;"; + break; + } + } + } + else + { + ProxyPtr prx = ProxyPtr::dynamicCast(type); + if(prx) + { + out << nl << "return 0;"; + } + else + { + ClassDeclPtr cl = ClassDeclPtr::dynamicCast(type); + if(cl) + { + out << nl << "return 0;"; + } + else + { + StructPtr st = StructPtr::dynamicCast(type); + if(st) + { + out << nl << "return " << fixKwd(st->scoped()) << "();"; + } + else + { + EnumPtr en = EnumPtr::dynamicCast(type); + if(en) + { + EnumeratorList enumerators = en->getEnumerators(); + out << nl << "return " << fixKwd(en->scope()) << fixKwd(enumerators.front()->name()) << ';'; + } + else + { + SequencePtr seq = SequencePtr::dynamicCast(type); + if(seq) + { + out << nl << "return " << fixKwd(seq->scoped()) << "();"; + } + else + { + DictionaryPtr dict = DictionaryPtr::dynamicCast(type); + assert(dict); + out << nl << "return " << fixKwd(dict->scoped()) << "();"; + } + } + } + } + } + } +} + +bool +Slice::Gen::ImplVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasClassDefs()) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::ImplVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp; + H << nl << '}'; +} + +bool +Slice::Gen::ImplVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + if(!p->isAbstract()) + { + return false; + } + + string name = p->name(); + string scope = fixKwd(p->scope()); + string cls = scope.substr(2) + name + "I"; + string classScopedAMD = scope + "AMD_" + name; + + ClassList bases = p->bases(); + ClassDefPtr base; + if(!bases.empty() && !bases.front()->isInterface()) + { + base = bases.front(); + } + + H << sp; + H << nl << "class " << name << "I : "; + H.useCurrentPosAsIndent(); + H << "virtual public " << fixKwd(name); + for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) + { + H << ',' << nl << "virtual public " << fixKwd((*q)->scope()); + if((*q)->isAbstract()) + { + H << (*q)->name() << "I"; + } + else + { + H << fixKwd((*q)->name()); + } + } + H.restoreIndent(); + + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + OperationList ops = p->operations(); + OperationList::const_iterator r; + + for(r = ops.begin(); r != ops.end(); ++r) + { + OperationPtr op = (*r); + string opName = op->name(); + + TypePtr ret = op->returnType(); + string retS = returnTypeToString(ret); + + if(!p->isLocal() && (p->hasMetaData("amd") || op->hasMetaData("amd"))) + { + H << sp << nl << "virtual void " << opName << "_async("; + H.useCurrentPosAsIndent(); + H << "const " << classScopedAMD << '_' << opName << "Ptr&"; + ParamDeclList paramList = op->parameters(); + ParamDeclList::const_iterator q; + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if(!(*q)->isOutParam()) + { + H << ',' << nl << inputTypeToString((*q)->type()); + } + } + H << ',' << nl << "const Ice::Current&"; + H.restoreIndent(); + + bool nonmutating = op->mode() == Operation::Nonmutating; + + H << ")" << (nonmutating ? " const" : "") << ';'; + + C << sp << nl << "void" << nl << scope << name << "I::" << opName << "_async("; + C.useCurrentPosAsIndent(); + C << "const " << classScopedAMD << '_' << opName << "Ptr& " << opName << "CB"; + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if(!(*q)->isOutParam()) + { + C << ',' << nl << inputTypeToString((*q)->type()) << ' ' << fixKwd((*q)->name()); + } + } + C << ',' << nl << "const Ice::Current& current"; + C.restoreIndent(); + C << ")" << (nonmutating ? " const" : ""); + C << sb; + + string result = "r"; + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->name() == result) + { + result = "_" + result; + break; + } + } + if(ret) + { + writeDecl(C, result, ret); + } + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + writeDecl(C, fixKwd((*q)->name()), (*q)->type()); + } + } + + C << nl << opName << "CB->ice_response("; + if(ret) + { + C << result; + } + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + if(ret || q != paramList.begin()) + { + C << ", "; + } + C << fixKwd((*q)->name()); + } + } + C << ");"; + + C << eb; + } + else + { + H << sp << nl << "virtual " << retS << ' ' << fixKwd(opName) << '('; + H.useCurrentPosAsIndent(); + ParamDeclList paramList = op->parameters(); + ParamDeclList::const_iterator q; + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if(q != paramList.begin()) + { + H << ',' << nl; + } +#if defined(__SUNPRO_CC) && (__SUNPRO_CC==0x550) + // + // Work around for Sun CC 5.5 bug #4853566 + // + string typeString; + if((*q)->isOutParam()) + { + typeString = outputTypeToString((*q)->type()); + } + else + { + typeString = inputTypeToString((*q)->type()); + } +#else + string typeString = (*q)->isOutParam() ? + outputTypeToString((*q)->type()) : inputTypeToString((*q)->type()); +#endif + H << typeString; + } + if(!p->isLocal()) + { + if(!paramList.empty()) + { + H << ',' << nl; + } + H << "const Ice::Current&"; + } + H.restoreIndent(); + + bool nonmutating = op->mode() == Operation::Nonmutating; + + H << ")" << (nonmutating ? " const" : "") << ';'; + + C << sp << nl << retS << nl; + C << scope.substr(2) << name << "I::" << fixKwd(opName) << '('; + C.useCurrentPosAsIndent(); + for(q = paramList.begin(); q != paramList.end(); ++q) + { + if(q != paramList.begin()) + { + C << ',' << nl; + } +#if defined(__SUNPRO_CC) && (__SUNPRO_CC==0x550) + // + // Work around for Sun CC 5.5 bug #4853566 + // + string typeString; + if((*q)->isOutParam()) + { + typeString = outputTypeToString((*q)->type()); + } + else + { + typeString = inputTypeToString((*q)->type()); + } +#else + string typeString = (*q)->isOutParam() ? + outputTypeToString((*q)->type()) : inputTypeToString((*q)->type()); +#endif + C << typeString << ' ' << fixKwd((*q)->name()); + } + if(!p->isLocal()) + { + if(!paramList.empty()) + { + C << ',' << nl; + } + C << "const Ice::Current& current"; + } + C.restoreIndent(); + C << ')'; + C << (nonmutating ? " const" : ""); + C << sb; + + if(ret) + { + writeReturn(C, ret); + } + + C << eb; + } + } + + H << eb << ';'; + + return true; +} + +Slice::Gen::AsyncVisitor::AsyncVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::AsyncVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls() || (!p->hasContentsWithMetaData("ami") && !p->hasContentsWithMetaData("amd"))) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::AsyncVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +void +Slice::Gen::AsyncVisitor::visitOperation(const OperationPtr& p) +{ + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + + if(cl->isLocal() || + (!cl->hasMetaData("ami") && !p->hasMetaData("ami") && !cl->hasMetaData("amd") && !p->hasMetaData("amd"))) + { + return; + } + + string name = p->name(); + + string className = cl->name(); + string classNameAMI = "AMI_" + className; + string classNameAMD = "AMD_" + className; + string classScope = fixKwd(cl->scope()); + string classScopedAMI = classScope + classNameAMI; + string classScopedAMD = classScope + classNameAMD; + string proxyName = classScope + className + "Prx"; + + vector<string> params; + vector<string> paramsDecl; + vector<string> args; + + vector<string> paramsInvoke; + vector<string> paramsDeclInvoke; + + paramsInvoke.push_back("const " + proxyName + "&"); + paramsDeclInvoke.push_back("const " + proxyName + "& __prx"); + + TypePtr ret = p->returnType(); + string retS = inputTypeToString(ret); + + if(ret) + { + params.push_back(retS); + paramsDecl.push_back(retS + " __ret"); + args.push_back("__ret"); + } + + TypeStringList inParams; + TypeStringList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + string paramName = fixKwd((*q)->name()); + TypePtr type = (*q)->type(); + string typeString = inputTypeToString(type); + + if((*q)->isOutParam()) + { + params.push_back(typeString); + paramsDecl.push_back(typeString + ' ' + paramName); + args.push_back(paramName); + + outParams.push_back(make_pair(type, paramName)); + } + else + { + paramsInvoke.push_back(typeString); + paramsDeclInvoke.push_back(typeString + ' ' + paramName); + + inParams.push_back(make_pair(type, paramName)); + } + } + + paramsInvoke.push_back("const ::Ice::Context&"); + paramsDeclInvoke.push_back("const ::Ice::Context& __ctx"); + + if(cl->hasMetaData("ami") || p->hasMetaData("ami")) + { + H << sp << nl << "class " << _dllExport << classNameAMI << '_' << name + << " : public ::IceInternal::OutgoingAsync"; + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + H << sp; + H << nl << "virtual void ice_response" << spar << params << epar << " = 0;"; + H << nl << "virtual void ice_exception(const ::Ice::Exception&) = 0;"; + H << sp; + H << nl << "void __invoke" << spar << paramsInvoke << epar << ';'; + H << sp; + H.dec(); + H << nl << "protected:"; + H.inc(); + H << sp; + H << nl << "virtual void __response(bool);"; + H << eb << ';'; + H << sp << nl << "typedef ::IceUtil::Handle< " << classScopedAMI << '_' << name << "> " << classNameAMI + << '_' << name << "Ptr;"; + + C << sp << nl << "void" << nl << classScopedAMI.substr(2) << '_' << name << "::__invoke" << spar + << paramsDeclInvoke << epar; + C << sb; + C << nl << "try"; + C << sb; + C << nl << "static const ::std::string __operation(\"" << name << "\");"; + C << nl << "__prepare(__prx, __operation, static_cast< ::Ice::OperationMode>(" << p->mode() << "), __ctx);"; + writeMarshalCode(C, inParams, 0); + if(p->sendsClasses()) + { + C << nl << "__os->writePendingObjects();"; + } + C << nl << "__os->endWriteEncaps();"; + C << eb; + C << nl << "catch(const ::Ice::LocalException& __ex)"; + C << sb; + C << nl << "__finished(__ex);"; + C << nl << "return;"; + C << eb; + C << nl << "__send();"; + C << eb; + + C << sp << nl << "void" << nl << classScopedAMI.substr(2) << '_' << name << "::__response(bool __ok)"; + C << sb; + writeAllocateCode(C, outParams, ret); + C << nl << "try"; + C << sb; + C << nl << "if(!__ok)"; + C << sb; + C << nl << "__is->throwException();"; + C << eb; + writeUnmarshalCode(C, outParams, ret); + if(p->returnsClasses()) + { + C << nl << "__is->readPendingObjects();"; + } + C << eb; + C << nl << "catch(const ::Ice::LocalException& __ex)"; + C << sb; + C << nl << "__finished(__ex);"; + C << nl << "return;"; + C << eb; + + // + // Generate a catch block for each legal user exception. + // (See comment in DelegateMVisitor::visitOperation() for details.) + // + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); +#if defined(__SUNPRO_CC) + throws.sort(derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + for(ExceptionList::const_iterator i = throws.begin(); i != throws.end(); ++i) + { + string scoped = (*i)->scoped(); + C << nl << "catch(const " << fixKwd((*i)->scoped()) << "& __ex)"; + C << sb; + C << nl << "ice_exception(__ex);"; + C << nl << "return;"; + C << eb; + } + C << nl << "catch(const ::Ice::UserException&)"; + C << sb; + C << nl << "ice_exception(::Ice::UnknownUserException(__FILE__, __LINE__));"; + C << nl << "return;"; + C << eb; + C << nl << "ice_response" << spar << args << epar << ';'; + C << eb; + } + + if(cl->hasMetaData("amd") || p->hasMetaData("amd")) + { + H << sp << nl << "class " << _dllExport << classNameAMD << '_' << name + << " : virtual public ::IceUtil::Shared"; + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + H << sp; + H << nl << "virtual void ice_response" << spar << params << epar << " = 0;"; + H << nl << "virtual void ice_exception(const ::Ice::Exception&) = 0;"; + H << nl << "virtual void ice_exception(const ::std::exception&) = 0;"; + H << nl << "virtual void ice_exception() = 0;"; + H << eb << ';'; + H << sp << nl << "typedef ::IceUtil::Handle< " << classScopedAMD << '_' << name << "> " + << classNameAMD << '_' << name << "Ptr;"; + } +} + +Slice::Gen::AsyncImplVisitor::AsyncImplVisitor(Output& h, Output& c, const string& dllExport) : + H(h), C(c), _dllExport(dllExport) +{ +} + +bool +Slice::Gen::AsyncImplVisitor::visitUnitStart(const UnitPtr& p) +{ + if(!p->hasNonLocalClassDecls() || !p->hasContentsWithMetaData("amd")) + { + return false; + } + + H << sp << nl << "namespace IceAsync" << nl << '{'; + + return true; +} + +void +Slice::Gen::AsyncImplVisitor::visitUnitEnd(const UnitPtr& p) +{ + H << sp << nl << '}'; +} + +bool +Slice::Gen::AsyncImplVisitor::visitModuleStart(const ModulePtr& p) +{ + if(!p->hasNonLocalClassDecls() || !p->hasContentsWithMetaData("amd")) + { + return false; + } + + string name = fixKwd(p->name()); + + H << sp << nl << "namespace " << name << nl << '{'; + + return true; +} + +void +Slice::Gen::AsyncImplVisitor::visitModuleEnd(const ModulePtr& p) +{ + H << sp << nl << '}'; +} + +void +Slice::Gen::AsyncImplVisitor::visitOperation(const OperationPtr& p) +{ + ContainerPtr container = p->container(); + ClassDefPtr cl = ClassDefPtr::dynamicCast(container); + + if(cl->isLocal() || (!cl->hasMetaData("amd") && !p->hasMetaData("amd"))) + { + return; + } + + string name = p->name(); + + string classNameAMD = "AMD_" + cl->name(); + string classScope = fixKwd(cl->scope()); + string classScopedAMD = classScope + classNameAMD; + + string params; + string paramsDecl; + string args; + + ExceptionList throws = p->throws(); + throws.sort(); + throws.unique(); + + // + // 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. + // +#if defined(__SUNPRO_CC) + throws.sort(derivedToBaseCompare); +#else + throws.sort(Slice::DerivedToBaseCompare()); +#endif + + TypePtr ret = p->returnType(); + string retS = inputTypeToString(ret); + + if(ret) + { + params += retS; + paramsDecl += retS; + paramsDecl += ' '; + paramsDecl += "__ret"; + args += "__ret"; + } + + TypeStringList outParams; + ParamDeclList paramList = p->parameters(); + for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) + { + if((*q)->isOutParam()) + { + string paramName = fixKwd((*q)->name()); + TypePtr type = (*q)->type(); + string typeString = inputTypeToString(type); + + if(ret || !outParams.empty()) + { + params += ", "; + paramsDecl += ", "; + args += ", "; + } + + params += typeString; + paramsDecl += typeString; + paramsDecl += ' '; + paramsDecl += paramName; + args += paramName; + + outParams.push_back(make_pair(type, paramName)); + } + } + + H << sp << nl << "class " << _dllExport << classNameAMD << '_' << name + << " : public " << classScopedAMD << '_' << name << ", public ::IceInternal::IncomingAsync"; + H << sb; + H.dec(); + H << nl << "public:"; + H.inc(); + + H << sp; + H << nl << classNameAMD << '_' << name << "(::IceInternal::Incoming&);"; + + H << sp; + H << nl << "virtual void ice_response(" << params << ");"; + H << nl << "virtual void ice_exception(const ::Ice::Exception&);"; + H << nl << "virtual void ice_exception(const ::std::exception&);"; + H << nl << "virtual void ice_exception();"; + H << eb << ';'; + + C << sp << nl << "IceAsync" << classScopedAMD << '_' << name << "::" << classNameAMD << '_' << name + << "(::IceInternal::Incoming& in) :"; + C.inc(); + C << nl << "IncomingAsync(in)"; + C.dec(); + C << sb; + C << eb; + + C << sp << nl << "void" << nl << "IceAsync" << classScopedAMD << '_' << name << "::ice_response(" + << paramsDecl << ')'; + C << sb; + if(ret || !outParams.empty()) + { + C << nl << "try"; + C << sb; + C << nl << "::IceInternal::BasicStream* __os = this->__os();"; + writeMarshalCode(C, outParams, ret); + if(p->returnsClasses()) + { + C << nl << "__os->writePendingObjects();"; + } + C << eb; + C << nl << "catch(const ::Ice::Exception& __ex)"; + C << sb; + C << nl << "__exception(__ex);"; + C << nl << "return;"; + C << eb; + } + C << nl << "__response(true);"; + C << eb; + + C << sp << nl << "void" << nl << "IceAsync" << classScopedAMD << '_' << name + << "::ice_exception(const ::Ice::Exception& ex)"; + C << sb; + if(throws.empty()) + { + C << nl << "__exception(ex);"; + } + else + { + C << nl << "try"; + C << sb; + C << nl << "ex.ice_throw();"; + C << eb; + ExceptionList::const_iterator r; + for(r = throws.begin(); r != throws.end(); ++r) + { + C << nl << "catch(const " << fixKwd((*r)->scoped()) << "& __ex)"; + C << sb; + C << nl << "__os()->write(__ex);"; + if((*r)->usesClasses()) + { + C << nl << "__os()->writePendingObjects();"; + } + C << nl << "__response(false);"; + C << eb; + } + C << nl << "catch(const ::Ice::Exception& __ex)"; + C << sb; + C << nl << "__exception(__ex);"; + C << eb; + } + C << eb; + + C << sp << nl << "void" << nl << "IceAsync" << classScopedAMD << '_' << name + << "::ice_exception(const ::std::exception& ex)"; + C << sb; + C << nl << "__exception(ex);"; + C << eb; + + C << sp << nl << "void" << nl << "IceAsync" << classScopedAMD << '_' << name + << "::ice_exception()"; + C << sb; + C << nl << "__exception();"; + C << eb; +} + +void +Slice::Gen::validateMetaData(const UnitPtr& unit) +{ + MetaDataVisitor visitor; + unit->visit(&visitor, false); +} + +bool +Slice::Gen::MetaDataVisitor::visitModuleStart(const ModulePtr& p) +{ + validate(p); + return true; +} + +void +Slice::Gen::MetaDataVisitor::visitModuleEnd(const ModulePtr&) +{ +} + +void +Slice::Gen::MetaDataVisitor::visitClassDecl(const ClassDeclPtr& p) +{ + validate(p); +} + +bool +Slice::Gen::MetaDataVisitor::visitClassDefStart(const ClassDefPtr& p) +{ + validate(p); + return true; +} + +void +Slice::Gen::MetaDataVisitor::visitClassDefEnd(const ClassDefPtr&) +{ +} + +bool +Slice::Gen::MetaDataVisitor::visitExceptionStart(const ExceptionPtr& p) +{ + validate(p); + return true; +} + +void +Slice::Gen::MetaDataVisitor::visitExceptionEnd(const ExceptionPtr&) +{ +} + +bool +Slice::Gen::MetaDataVisitor::visitStructStart(const StructPtr& p) +{ + validate(p); + return true; +} + +void +Slice::Gen::MetaDataVisitor::visitStructEnd(const StructPtr&) +{ +} + +void +Slice::Gen::MetaDataVisitor::visitOperation(const OperationPtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::visitParamDecl(const ParamDeclPtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::visitDataMember(const DataMemberPtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::visitSequence(const SequencePtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::visitDictionary(const DictionaryPtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::visitEnum(const EnumPtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::visitConst(const ConstPtr& p) +{ + validate(p); +} + +void +Slice::Gen::MetaDataVisitor::validate(const ContainedPtr& cont) +{ + DefinitionContextPtr dc = cont->definitionContext(); + assert(dc); + StringList globalMetaData = dc->getMetaData(); + string file = dc->filename(); + + StringList localMetaData = cont->getMetaData(); + + StringList::const_iterator p; + static const string prefix = "cpp:"; + + for(p = globalMetaData.begin(); p != globalMetaData.end(); ++p) + { + string s = *p; + if(_history.count(s) == 0) + { + if(s.find(prefix) == 0) + { + cout << file << ": warning: ignoring invalid global metadata `" << s << "'" << endl; + } + _history.insert(s); + } + } + + for(p = localMetaData.begin(); p != localMetaData.end(); ++p) + { + string s = *p; + if(_history.count(s) == 0) + { + if(s.find(prefix) == 0) + { + if(SequencePtr::dynamicCast(cont)) + { + if(s.substr(prefix.size()) == "collection") + { + continue; + } + } + if(StructPtr::dynamicCast(cont)) + { + if(s.substr(prefix.size()) == "class") + { + continue; + } + } + cout << file << ": warning: ignoring invalid metadata `" << s << "'" << endl; + } + _history.insert(s); + } + } +} |