bool FreezeScript::AnalyzeTransformVisitor::checkClasses(const ClassDeclPtr& from, const ClassDeclPtr& to) { string fromScoped = from->scoped(); string toScoped = to->scoped(); if(fromScoped == toScoped) { return true; } // // The types don't match, so check them for compatibility. Specifically, // look up the old type id in the new Slice and see if it has the target // type as a base class. // TypeList l = to->unit()->lookupTypeNoBuiltin(from->scoped(), false); if(!l.empty()) { ClassDeclPtr decl = ClassDeclPtr::dynamicCast(l.front()); if(decl) { ClassDefPtr def = decl->definition(); if(def) { ClassList bases = def->allBases(); for(ClassList::iterator p = bases.begin(); p != bases.end(); ++p) { if((*p)->scoped() == toScoped) { return true; } } } } } return false; }
bool Slice::Ruby::CodeVisitor::visitClassDefStart(const ClassDefPtr& p) { string scoped = p->scoped(); string name = fixIdent(p->name(), IdentToUpper); ClassList bases = p->bases(); ClassDefPtr base; OperationList ops = p->operations(); OperationList::iterator oli; // // Define a mix-in module for the class. // _out << sp << nl << "if not defined?(" << getAbsolute(p, IdentToUpper) << "_mixin)"; _out.inc(); _out << nl << "module " << name << "_mixin"; _out.inc(); if(!p->isLocal()) { if(!bases.empty() && !bases.front()->isInterface()) { base = bases.front(); _out << nl << "include " << getAbsolute(bases.front(), IdentToUpper) << "_mixin"; } else { _out << nl << "include ::Ice::Object_mixin"; } // // ice_ids // 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(scoped); other.push_back("::Ice::Object"); other.sort(); ids.merge(other); ids.unique(); _out << sp << nl << "def ice_ids(current=nil)"; _out.inc(); _out << nl << "["; for(StringList::iterator q = ids.begin(); q != ids.end(); ++q) { if(q != ids.begin()) { _out << ", "; } _out << "'" << *q << "'"; } _out << ']'; _out.dec(); _out << nl << "end"; // // ice_id // _out << sp << nl << "def ice_id(current=nil)"; _out.inc(); _out << nl << "'" << scoped << "'"; _out.dec(); _out << nl << "end"; } if(!ops.empty()) { // // Emit a comment for each operation. // _out << sp << nl << "#" << nl << "# Operation signatures." << nl << "#"; for(oli = ops.begin(); oli != ops.end(); ++oli) { string fixedOpName = fixIdent((*oli)->name(), IdentNormal); /* If AMI/AMD is ever implemented... if(!p->isLocal() && (p->hasMetaData("amd") || (*oli)->hasMetaData("amd"))) { _out << nl << "# def " << fixedOpName << "_async(_cb"; ParamDeclList params = (*oli)->parameters(); for(ParamDeclList::iterator pli = params.begin(); pli != params.end(); ++pli) { if(!(*pli)->isOutParam()) { _out << ", " << fixIdent((*pli)->name(), IdentToLower); } } if(!p->isLocal()) { _out << ", current=nil"; } _out << ")"; } else */ { _out << nl << "# def " << fixedOpName << "("; ParamDeclList params = (*oli)->parameters(); bool first = true; for(ParamDeclList::iterator pli = params.begin(); pli != params.end(); ++pli) { if(!(*pli)->isOutParam()) { if(first) { first = false; } else { _out << ", "; } _out << fixIdent((*pli)->name(), IdentToLower); } } if(!p->isLocal()) { if(!first) { _out << ", "; } _out << "current=nil"; } _out << ")"; } } } // // inspect // _out << sp << nl << "def inspect"; _out.inc(); _out << nl << "::Ice::__stringify(self, T_" << name << ")"; _out.dec(); _out << nl << "end"; // // read/write accessors for data members. // DataMemberList members = p->dataMembers(); if(!members.empty()) { bool prot = p->hasMetaData("protected"); DataMemberList protectedMembers; DataMemberList::iterator q; _out << sp << nl << "attr_accessor "; for(q = members.begin(); q != members.end(); ++q) { if(q != members.begin()) { _out << ", "; } _out << ":" << fixIdent((*q)->name(), IdentNormal); if(prot || (*q)->hasMetaData("protected")) { protectedMembers.push_back(*q); } } if(!protectedMembers.empty()) { _out << nl << "protected "; for(q = protectedMembers.begin(); q != protectedMembers.end(); ++q) { if(q != protectedMembers.begin()) { _out << ", "; } // // We need to list the symbols of the reader and the writer (e.g., ":member" and ":member="). // _out << ":" << fixIdent((*q)->name(), IdentNormal) << ", :" << fixIdent((*q)->name(), IdentNormal) << '='; } } } _out.dec(); _out << nl << "end"; // End of mix-in module for class. if(p->isInterface()) { // // Class. // _out << nl << "class " << name; _out.inc(); _out << nl << "include " << name << "_mixin"; _out << nl; _out << nl << "def " << name << ".ice_staticId()"; _out.inc(); _out << nl << "'" << scoped << "'"; _out.dec(); _out << nl << "end"; _out.dec(); _out << nl << "end"; } else { // // Class. // _out << nl << "class " << name; if(base) { _out << " < " << getAbsolute(base, IdentToUpper); } _out.inc(); _out << nl << "include " << name << "_mixin"; _out << nl; _out << nl << "def " << name << ".ice_staticId()"; _out.inc(); _out << nl << "'" << scoped << "'"; _out.dec(); _out << nl << "end"; // // initialize // MemberInfoList allMembers; collectClassMembers(p, allMembers, false); if(!allMembers.empty()) { _out << sp << nl << "def initialize("; writeConstructorParams(allMembers); _out << ')'; _out.inc(); MemberInfoList::iterator q; bool inheritsMembers = false; for(q = allMembers.begin(); q != allMembers.end(); ++q) { if(q->inherited) { inheritsMembers = true; break; } } if(inheritsMembers) { _out << nl << "super" << spar; for(q = allMembers.begin(); q != allMembers.end(); ++q) { if(q->inherited) { _out << q->lowerName; } } _out << epar; } for(q = allMembers.begin(); q != allMembers.end(); ++q) { if(!q->inherited) { _out << nl << '@' << q->fixedName << " = " << q->lowerName; } } _out.dec(); _out << nl << "end"; } _out.dec(); _out << nl << "end"; // End of class. } // // Generate proxy support. This includes a mix-in module for the proxy's // operations and a class for the proxy itself. // if(!p->isLocal()) { _out << nl << "module " << name << "Prx_mixin"; _out.inc(); for(ClassList::iterator cli = bases.begin(); cli != bases.end(); ++cli) { _out << nl << "include " << getAbsolute(*cli, IdentToUpper) << "Prx_mixin"; } for(oli = ops.begin(); oli != ops.end(); ++oli) { string fixedOpName = fixIdent((*oli)->name(), IdentNormal); if(fixedOpName == "checkedCast" || fixedOpName == "uncheckedCast") { fixedOpName.insert(0, "_"); } TypePtr ret = (*oli)->returnType(); ParamDeclList paramList = (*oli)->parameters(); string inParams; for(ParamDeclList::const_iterator q = paramList.begin(); q != paramList.end(); ++q) { if(!(*q)->isOutParam()) { if(!inParams.empty()) { inParams.append(", "); } inParams.append(fixIdent((*q)->name(), IdentToLower)); } } _out << sp << nl << "def " << fixedOpName << "("; if(!inParams.empty()) { _out << inParams << ", "; } _out << "_ctx=nil)"; _out.inc(); _out << nl << name << "_mixin::OP_" << (*oli)->name() << ".invoke(self, [" << inParams; _out << "], _ctx)"; _out.dec(); _out << nl << "end"; /* If AMI/AMD is ever implemented... if(p->hasMetaData("ami") || (*oli)->hasMetaData("ami")) { _out << sp << nl << "def " << fixedOpName << "_async(_cb"; if(!inParams.empty()) { _out << ", " << inParams; } _out << ", _ctx=nil)"; _out.inc(); _out << nl << name << "_mixin::OP_" << (*oli)->name() << ".invokeAsync(self, _cb, [" << inParams; if(!inParams.empty() && inParams.find(',') == string::npos) { _out << ", "; } _out << "], _ctx)"; _out.dec(); _out << nl << "end"; } */ } _out.dec(); _out << nl << "end"; // End of mix-in module for proxy. _out << nl << "class " << name << "Prx < ::Ice::ObjectPrx"; _out.inc(); _out << nl << "include " << name << "Prx_mixin"; _out << sp << nl << "def " << name << "Prx.checkedCast(proxy, facetOrCtx=nil, _ctx=nil)"; _out.inc(); _out << nl << "ice_checkedCast(proxy, '" << scoped << "', facetOrCtx, _ctx)"; _out.dec(); _out << nl << "end"; _out << sp << nl << "def " << name << "Prx.uncheckedCast(proxy, facet=nil)"; _out.inc(); _out << nl << "ice_uncheckedCast(proxy, facet)"; _out.dec(); _out << nl << "end"; _out.dec(); _out << nl << "end"; // End of proxy class. } // // Emit type descriptions. // _out << sp << nl << "if not defined?(" << getAbsolute(p, IdentToUpper, "T_") << ')'; _out.inc(); if(p->isLocal()) { _out << nl << "T_" << name << " = ::Ice::__declareLocalClass('" << scoped << "')"; } else { _out << nl << "T_" << name << " = ::Ice::__declareClass('" << scoped << "')"; _out << nl << "T_" << name << "Prx = ::Ice::__declareProxy('" << scoped << "')"; } _out.dec(); _out << nl << "end"; _classHistory.insert(scoped); // Avoid redundant declarations. bool isAbstract = p->isInterface() || p->allOperations().size() > 0; // Don't use isAbstract() here - see bug 3739 _out << sp << nl << "T_" << name << ".defineClass(" << name << ", " << (isAbstract ? "true" : "false") << ", "; if(!base) { _out << "nil"; } else { _out << getAbsolute(base, IdentToUpper, "T_"); } _out << ", ["; // // Interfaces // // TODO: Necessary? // { int interfaceCount = 0; for(ClassList::const_iterator q = bases.begin(); q != bases.end(); ++q) { if((*q)->isInterface()) { if(interfaceCount > 0) { _out << ", "; } _out << getAbsolute(*q, IdentToUpper, "T_"); ++interfaceCount; } } } // // Members // // Data members are represented as an array: // // ['MemberName', MemberType] // // where MemberType is either a primitive type constant (T_INT, etc.) or the id of a constructed type. // _out << "], ["; if(members.size() > 1) { _out.inc(); _out << nl; } { for(DataMemberList::iterator q = members.begin(); q != members.end(); ++q) { if(q != members.begin()) { _out << ',' << nl; } _out << "['" << fixIdent((*q)->name(), IdentNormal) << "', "; writeType((*q)->type()); _out << ']'; } } if(members.size() > 1) { _out.dec(); _out << nl; } _out << "])"; _out << nl << name << "_mixin::ICE_TYPE = T_" << name; // // Define each operation. The arguments to __defineOperation are: // // 'opName', Mode, [InParams], [OutParams], ReturnType, [Exceptions] // // where InParams and OutParams are arrays of type descriptions, and Exceptions // is an array of exception types. // if(!p->isLocal()) { _out << sp << nl << "T_" << name << "Prx.defineProxy(" << name << "Prx, T_" << name << ')'; _out << nl << name << "Prx::ICE_TYPE = T_" << name << "Prx"; if(!ops.empty()) { _out << sp; } for(OperationList::iterator s = ops.begin(); s != ops.end(); ++s) { ParamDeclList params = (*s)->parameters(); ParamDeclList::iterator t; int count; _out << nl << name << "_mixin::OP_" << (*s)->name() << " = ::Ice::__defineOperation('" << (*s)->name() << "', "; switch((*s)->mode()) { case Operation::Normal: _out << "::Ice::OperationMode::Normal"; break; case Operation::Nonmutating: _out << "::Ice::OperationMode::Nonmutating"; break; case Operation::Idempotent: _out << "::Ice::OperationMode::Idempotent"; break; } _out << ", "; switch((*s)->sendMode()) { case Operation::Normal: _out << "::Ice::OperationMode::Normal"; break; case Operation::Nonmutating: _out << "::Ice::OperationMode::Nonmutating"; break; case Operation::Idempotent: _out << "::Ice::OperationMode::Idempotent"; break; } _out << ", " << ((p->hasMetaData("amd") || (*s)->hasMetaData("amd")) ? "true" : "false") << ", ["; for(t = params.begin(), count = 0; t != params.end(); ++t) { if(!(*t)->isOutParam()) { if(count > 0) { _out << ", "; } writeType((*t)->type()); ++count; } } _out << "], ["; for(t = params.begin(), count = 0; t != params.end(); ++t) { if((*t)->isOutParam()) { if(count > 0) { _out << ", "; } writeType((*t)->type()); ++count; } } _out << "], "; TypePtr returnType = (*s)->returnType(); if(returnType) { writeType(returnType); } else { _out << "nil"; } _out << ", ["; ExceptionList exceptions = (*s)->throws(); for(ExceptionList::iterator u = exceptions.begin(); u != exceptions.end(); ++u) { if(u != exceptions.begin()) { _out << ", "; } _out << getAbsolute(*u, IdentToUpper, "T_"); } _out << "])"; string deprecateMetadata; if((*s)->findMetaData("deprecate", deprecateMetadata) || p->findMetaData("deprecate", deprecateMetadata)) { string msg; string::size_type pos = deprecateMetadata.find(':'); if(pos != string::npos && pos < deprecateMetadata.size() - 1) { msg = deprecateMetadata.substr(pos + 1); } _out << nl << name << "_mixin::OP_" << (*s)->name() << ".deprecate(\"" << msg << "\")"; } } } _out.dec(); _out << nl << "end"; // if not defined?() return false; }