// // Copyright (c) ZeroC, Inc. All rights reserved. // #include #include #include #include #include #include #include #include // TODO: fix this warning once we no longer support VS2013 and earlier #if defined(_MSC_VER) && (_MSC_VER >= 1900) # pragma warning(disable:4589) // Constructor of abstract class 'Slice::Type' ignores initializer... #endif using namespace std; using namespace Slice; Slice::CompilerException::CompilerException(const char* file, int line, const string& r) : IceUtil::Exception(file, line), _reason(r) { } #ifndef ICE_CPP11_COMPILER Slice::CompilerException::~CompilerException() throw() { } #endif string Slice::CompilerException::ice_id() const { return "::Slice::CompilerException"; } void Slice::CompilerException::ice_print(ostream& out) const { IceUtil::Exception::ice_print(out); out << ": " << _reason; } #ifndef ICE_CPP11_MAPPING Slice::CompilerException* Slice::CompilerException::ice_clone() const { return new CompilerException(*this); } #endif void Slice::CompilerException::ice_throw() const { throw *this; } string Slice::CompilerException::reason() const { return _reason; } extern FILE* slice_in; extern int slice_debug; int slice_parse(); // // Operation attributes // // read + supports must be 0 (the default) // namespace { string readWriteAttribute[] = { "read", "write" }; string txAttribute[] = { "supports", "mandatory", "required", "never" }; enum { Supports, Mandatory, Required, Never }; DataMemberList filterOrderedOptionalDataMembers(const DataMemberList& members) { class SortFn { public: static bool compare(const DataMemberPtr& lhs, const DataMemberPtr& rhs) { return lhs->tag() < rhs->tag(); } }; DataMemberList result; for(DataMemberList::const_iterator p = members.begin(); p != members.end(); ++p) { if((*p)->optional()) { result.push_back(*p); } } result.sort(SortFn::compare); return result; } void sortOptionalParameters(ParamDeclList& params) { // // Sort optional parameters by tag. // class SortFn { public: static bool compare(const ParamDeclPtr& lhs, const ParamDeclPtr& rhs) { return lhs->tag() < rhs->tag(); } }; params.sort(SortFn::compare); } bool isMutableAfterReturnType(const TypePtr& type) { // // Returns true if the type contains data types which can be referenced by user code // and mutated after a dispatch returns. // if(ClassDeclPtr::dynamicCast(type)) { return true; } BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); if(builtin && (builtin->kind() == Builtin::KindObject || builtin->kind() == Builtin::KindValue)) { return true; } if(SequencePtr::dynamicCast(type) || DictionaryPtr::dynamicCast(type)) { return true; } StructPtr s = StructPtr::dynamicCast(type); if(s) { return true; } return false; } void checkDeprecatedType(const UnitPtr& unt, const TypePtr& type) { ClassDeclPtr decl = ClassDeclPtr::dynamicCast(type); if(decl && !decl->isLocal() && decl->isInterface()) { unt->warning(Deprecated, "interface by value is deprecated"); } ProxyPtr proxy = ProxyPtr::dynamicCast(type); if(proxy && !proxy->_class()->isInterface()) { unt->warning(Deprecated, "proxy for a class is deprecated"); } } } namespace Slice { Unit* unit; } // ---------------------------------------------------------------------- // DefinitionContext // ---------------------------------------------------------------------- Slice::DefinitionContext::DefinitionContext(int includeLevel, const StringList& metaData) : _includeLevel(includeLevel), _metaData(metaData), _seenDefinition(false) { initSuppressedWarnings(); } string Slice::DefinitionContext::filename() const { return _filename; } int Slice::DefinitionContext::includeLevel() const { return _includeLevel; } bool Slice::DefinitionContext::seenDefinition() const { return _seenDefinition; } void Slice::DefinitionContext::setFilename(const string& filename) { _filename = filename; } void Slice::DefinitionContext::setSeenDefinition() { _seenDefinition = true; } bool Slice::DefinitionContext::hasMetaData() const { return !_metaData.empty(); } void Slice::DefinitionContext::setMetaData(const StringList& metaData) { _metaData = metaData; initSuppressedWarnings(); } string Slice::DefinitionContext::findMetaData(const string& prefix) const { for(StringList::const_iterator p = _metaData.begin(); p != _metaData.end(); ++p) { if((*p).find(prefix) == 0) { return *p; } } return string(); } StringList Slice::DefinitionContext::getMetaData() const { return _metaData; } void Slice::DefinitionContext::warning(WarningCategory category, const string& file, int line, const string& msg) const { if(!suppressWarning(category)) { emitWarning(file, line, msg); } } void Slice::DefinitionContext::warning(WarningCategory category, const string& file, const string& line, const string& msg) const { if(!suppressWarning(category)) { emitWarning(file, line, msg); } } void Slice::DefinitionContext::error(const string& file, int line, const string& msg) const { emitError(file, line, msg); throw CompilerException(__FILE__, __LINE__, msg); } void Slice::DefinitionContext::error(const string& file, const string& line, const string& msg) const { emitError(file, line, msg); throw CompilerException(__FILE__, __LINE__, msg); } bool Slice::DefinitionContext::suppressWarning(WarningCategory category) const { return _suppressedWarnings.find(category) != _suppressedWarnings.end() || _suppressedWarnings.find(All) != _suppressedWarnings.end(); } void Slice::DefinitionContext::initSuppressedWarnings() { _suppressedWarnings.clear(); const string prefix = "suppress-warning"; string value = findMetaData(prefix); if(value == prefix) { _suppressedWarnings.insert(All); } else if(!value.empty()) { assert(value.length() > prefix.length()); if(value[prefix.length()] == ':') { value = value.substr(prefix.length() + 1); vector result; IceUtilInternal::splitString(value, ",", result); for(vector::iterator p = result.begin(); p != result.end(); ++p) { string s = IceUtilInternal::trim(*p); if(s == "all") { _suppressedWarnings.insert(All); } else if(s == "deprecated") { _suppressedWarnings.insert(Deprecated); } else if(s == "invalid-metadata") { _suppressedWarnings.insert(InvalidMetaData); } else { warning(InvalidMetaData, "", "", string("invalid category `") + s + "' in file metadata suppress-warning"); } } } } } // ---------------------------------------------------------------------- // Comment // ---------------------------------------------------------------------- bool Slice::Comment::isDeprecated() const { return _isDeprecated; } StringList Slice::Comment::deprecated() const { return _deprecated; } StringList Slice::Comment::overview() const { return _overview; } StringList Slice::Comment::misc() const { return _misc; } StringList Slice::Comment::seeAlso() const { return _seeAlso; } StringList Slice::Comment::returns() const { return _returns; } map Slice::Comment::parameters() const { return _parameters; } map Slice::Comment::exceptions() const { return _exceptions; } Slice::Comment::Comment() { } // ---------------------------------------------------------------------- // SyntaxTreeBase // ---------------------------------------------------------------------- void Slice::SyntaxTreeBase::destroy() { _unit = 0; } UnitPtr Slice::SyntaxTreeBase::unit() const { return _unit; } DefinitionContextPtr Slice::SyntaxTreeBase::definitionContext() const { return _definitionContext; } void Slice::SyntaxTreeBase::visit(ParserVisitor*, bool) { } Slice::SyntaxTreeBase::SyntaxTreeBase(const UnitPtr& unt, const DefinitionContextPtr& definitionContext) : _unit(unt), _definitionContext(definitionContext) { if(!_definitionContext && _unit) { _definitionContext = unt->currentDefinitionContext(); } } // ---------------------------------------------------------------------- // Type // ---------------------------------------------------------------------- Slice::Type::Type(const UnitPtr& unt) : SyntaxTreeBase(unt) { } // ---------------------------------------------------------------------- // Builtin // ---------------------------------------------------------------------- bool Slice::Builtin::isLocal() const { return _kind == KindLocalObject; } string Slice::Builtin::typeId() const { switch(_kind) { case KindByte: { return "byte"; break; } case KindBool: { return "bool"; break; } case KindShort: { return "short"; break; } case KindInt: { return "int"; break; } case KindLong: { return "long"; break; } case KindFloat: { return "float"; break; } case KindDouble: { return "double"; break; } case KindString: { return "string"; break; } case KindObject: { return "::Ice::Object"; break; } case KindObjectProxy: { return "::Ice::Object*"; break; } case KindLocalObject: { return "::Ice::LocalObject"; break; } case KindValue: { return "::Ice::Value"; break; } } assert(false); return ""; // Keep the compiler happy. } bool Slice::Builtin::usesClasses() const { return _kind == KindObject || _kind == KindValue; } size_t Slice::Builtin::minWireSize() const { static size_t minWireSizeTable[] = { 1, // KindByte 1, // KindBool 2, // KindShort 4, // KindInt 8, // KindLong 4, // KindFloat 8, // KindDouble 1, // KindString: at least one byte for an empty string. 1, // KindObject: at least one byte (to marshal an index instead of an instance). 2, // KindObjectProxy: at least an empty identity for a nil proxy, that is, 2 bytes. 0, // KindLocalObject: unused 1 // KindValue: at least one byte (to marshal an index instead of an instance). }; assert(_kind != KindLocalObject); return minWireSizeTable[_kind]; } bool Slice::Builtin::isVariableLength() const { return _kind == KindString || _kind == KindObject || _kind == KindObjectProxy || _kind == KindValue; } Builtin::Kind Slice::Builtin::kind() const { return _kind; } string Builtin::kindAsString() const { return builtinTable[_kind]; } const char* Slice::Builtin::builtinTable[] = { "byte", "bool", "short", "int", "long", "float", "double", "string", "Object", "Object*", "LocalObject", "Value" }; Slice::Builtin::Builtin(const UnitPtr& ut, Kind kind) : SyntaxTreeBase(ut), Type(ut), _kind(kind) { // // Builtin types do not have a definition context. // _definitionContext = 0; } // ---------------------------------------------------------------------- // Contained // ---------------------------------------------------------------------- ContainerPtr Slice::Contained::container() const { return _container; } string Slice::Contained::name() const { return _name; } string Slice::Contained::scoped() const { return _scoped; } string Slice::Contained::scope() const { string::size_type idx = _scoped.rfind("::"); assert(idx != string::npos); return string(_scoped, 0, idx + 2); } string Slice::Contained::flattenedScope() const { string s = scope(); string::size_type pos = 0; while((pos = s.find("::", pos)) != string::npos) { s.replace(pos, 2, "_"); } return s; } string Slice::Contained::file() const { return _file; } string Slice::Contained::line() const { return _line; } string Slice::Contained::comment() const { return _comment; } namespace { void trimLines(StringList& l) { // // Remove empty trailing lines. // while(!l.empty() && l.back().empty()) { l.pop_back(); } } StringList splitComment(const string& c, bool stripMarkup) { string comment = c; if(stripMarkup) { // // Strip HTML markup and javadoc links. // string::size_type pos = 0; do { pos = comment.find('<', pos); if(pos != string::npos) { string::size_type endpos = comment.find('>', pos); if(endpos == string::npos) { break; } comment.erase(pos, endpos - pos + 1); } } while(pos != string::npos); const string link = "{@link"; pos = 0; do { pos = comment.find(link, pos); if(pos != string::npos) { comment.erase(pos, link.size() + 1); // Erase trailing white space too. string::size_type endpos = comment.find('}', pos); if(endpos != string::npos) { string ident = comment.substr(pos, endpos - pos); comment.erase(pos, endpos - pos + 1); // // Replace links of the form {@link Type#member} with "Type.member". // string::size_type hash = ident.find('#'); string rest; if(hash != string::npos) { rest = ident.substr(hash + 1); ident = ident.substr(0, hash); if(!ident.empty()) { if(!rest.empty()) { ident += "." + rest; } } else if(!rest.empty()) { ident = rest; } } comment.insert(pos, ident); } } } while(pos != string::npos); } StringList result; string::size_type pos = 0; string::size_type nextPos; while((nextPos = comment.find_first_of('\n', pos)) != string::npos) { result.push_back(IceUtilInternal::trim(string(comment, pos, nextPos - pos))); pos = nextPos + 1; } string lastLine = IceUtilInternal::trim(string(comment, pos)); if(!lastLine.empty()) { result.push_back(lastLine); } trimLines(result); return result; } bool parseCommentLine(const string& l, const string& tag, bool namedTag, string& name, string& doc) { doc.clear(); if(l.find(tag) == 0) { const string ws = " \t"; if(namedTag) { string::size_type n = l.find_first_not_of(ws, tag.size()); if(n == string::npos) { return false; // Malformed line, ignore it. } string::size_type end = l.find_first_of(ws, n); if(end == string::npos) { return false; // Malformed line, ignore it. } name = l.substr(n, end - n); n = l.find_first_not_of(ws, end); if(n != string::npos) { doc = l.substr(n); } } else { name.clear(); string::size_type n = l.find_first_not_of(ws, tag.size()); if(n == string::npos) { return false; // Malformed line, ignore it. } doc = l.substr(n); } return true; } return false; } } CommentPtr Slice::Contained::parseComment(bool stripMarkup) const { CommentPtr comment = new Comment; comment->_isDeprecated = false; // // First check metadata for a deprecated tag. // string deprecateMetadata; if(findMetaData("deprecate", deprecateMetadata)) { comment->_isDeprecated = true; if(deprecateMetadata.find("deprecate:") == 0 && deprecateMetadata.size() > 10) { comment->_deprecated.push_back(IceUtilInternal::trim(deprecateMetadata.substr(10))); } } if(!comment->_isDeprecated && _comment.empty()) { return 0; } // // Split up the comment into lines. // StringList lines = splitComment(_comment, stripMarkup); StringList::const_iterator i; for(i = lines.begin(); i != lines.end(); ++i) { const string l = *i; if(l[0] == '@') { break; } comment->_overview.push_back(l); } enum State { StateMisc, StateParam, StateThrows, StateReturn, StateDeprecated }; State state = StateMisc; string name; const string ws = " \t"; const string paramTag = "@param"; const string throwsTag = "@throws"; const string exceptionTag = "@exception"; const string returnTag = "@return"; const string deprecatedTag = "@deprecated"; const string seeTag = "@see"; for(; i != lines.end(); ++i) { const string l = IceUtilInternal::trim(*i); string line; if(parseCommentLine(l, paramTag, true, name, line)) { if(!line.empty()) { state = StateParam; StringList sl; sl.push_back(line); // The first line of the description. comment->_parameters[name] = sl; } } else if(parseCommentLine(l, throwsTag, true, name, line)) { if(!line.empty()) { state = StateThrows; StringList sl; sl.push_back(line); // The first line of the description. comment->_exceptions[name] = sl; } } else if(parseCommentLine(l, exceptionTag, true, name, line)) { if(!line.empty()) { state = StateThrows; StringList sl; sl.push_back(line); // The first line of the description. comment->_exceptions[name] = sl; } } else if(parseCommentLine(l, seeTag, false, name, line)) { if(!line.empty()) { comment->_seeAlso.push_back(line); } } else if(parseCommentLine(l, returnTag, false, name, line)) { if(!line.empty()) { state = StateReturn; comment->_returns.push_back(line); // The first line of the description. } } else if(parseCommentLine(l, deprecatedTag, false, name, line)) { comment->_isDeprecated = true; if(!line.empty()) { state = StateDeprecated; comment->_deprecated.push_back(line); // The first line of the description. } } else if(!l.empty()) { if(l[0] == '@') { // // Treat all other tags as miscellaneous comments. // state = StateMisc; } switch(state) { case StateMisc: { comment->_misc.push_back(l); break; } case StateParam: { assert(!name.empty()); StringList sl; if(comment->_parameters.find(name) != comment->_parameters.end()) { sl = comment->_parameters[name]; } sl.push_back(l); comment->_parameters[name] = sl; break; } case StateThrows: { assert(!name.empty()); StringList sl; if(comment->_exceptions.find(name) != comment->_exceptions.end()) { sl = comment->_exceptions[name]; } sl.push_back(l); comment->_exceptions[name] = sl; break; } case StateReturn: { comment->_returns.push_back(l); break; } case StateDeprecated: { comment->_deprecated.push_back(l); break; } } } } trimLines(comment->_overview); trimLines(comment->_deprecated); trimLines(comment->_misc); trimLines(comment->_returns); return comment; } int Slice::Contained::includeLevel() const { return _includeLevel; } void Slice::Contained::updateIncludeLevel() { _includeLevel = min(_includeLevel, _unit->currentIncludeLevel()); } bool Slice::Contained::hasMetaData(const string& meta) const { return find(_metaData.begin(), _metaData.end(), meta) != _metaData.end(); } bool Slice::Contained::findMetaData(const string& prefix, string& meta) const { for(list::const_iterator p = _metaData.begin(); p != _metaData.end(); ++p) { if(p->find(prefix) == 0) { meta = *p; return true; } } return false; } list Slice::Contained::getMetaData() const { return _metaData; } void Slice::Contained::setMetaData(const list& metaData) { _metaData = metaData; } // // TODO: remove this method once "cs:" and "vb:" prefix are hard errors. // void Slice::Contained::addMetaData(const string& s) { _metaData.push_back(s); } FormatType Slice::Contained::parseFormatMetaData(const list& metaData) { FormatType result = DefaultFormat; string tag; string prefix = "format:"; for(list::const_iterator p = metaData.begin(); p != metaData.end(); ++p) { if(p->find(prefix) == 0) { tag = *p; break; } } if(!tag.empty()) { tag = tag.substr(prefix.size()); if(tag == "compact") { result = CompactFormat; } else if(tag == "sliced") { result = SlicedFormat; } else if(tag != "default") // TODO: Allow "default" to be specified as a format value? { // TODO: How to handle invalid format? } } return result; } bool Slice::Contained::operator<(const Contained& rhs) const { return _scoped < rhs._scoped; } bool Slice::Contained::operator==(const Contained& rhs) const { return _scoped == rhs._scoped; } Slice::Contained::Contained(const ContainerPtr& container, const string& name) : SyntaxTreeBase(container->unit()), _container(container), _name(name) { ContainedPtr cont = ContainedPtr::dynamicCast(_container); if(cont) { _scoped = cont->scoped(); } _scoped += "::" + _name; assert(_unit); _unit->addContent(this); _file = _unit->currentFile(); ostringstream s; s << _unit->currentLine(); _line = s.str(); _comment = _unit->currentComment(); _includeLevel = _unit->currentIncludeLevel(); } // ---------------------------------------------------------------------- // Container // ---------------------------------------------------------------------- void Slice::Container::destroy() { for_each(_contents.begin(), _contents.end(), ::IceUtil::voidMemFun(&SyntaxTreeBase::destroy)); _contents.clear(); _introducedMap.clear(); SyntaxTreeBase::destroy(); } ModulePtr Slice::Container::createModule(const string& name) { ContainedList matches = _unit->findContents(thisScope() + name); matches.sort(); // Modules can occur many times... matches.unique(); // ... but we only want one instance of each. if(thisScope() == "::") { _unit->addTopLevelModule(_unit->currentFile(), name); } for(ContainedList::const_iterator p = matches.begin(); p != matches.end(); ++p) { bool differsOnlyInCase = matches.front()->name() != name; ModulePtr module = ModulePtr::dynamicCast(*p); if(module) { if(differsOnlyInCase) // Modules can be reopened only if they are capitalized correctly. { string msg = "module `" + name + "' is capitalized inconsistently with its previous name: `"; msg += module->name() + "'"; _unit->error(msg); return 0; } } else if(!differsOnlyInCase) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as module"; _unit->error(msg); return 0; } else { string msg = "module `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " name `" + matches.front()->name() + "'"; _unit->error(msg); return 0; } } if(!nameIsLegal(name, "module")) { return 0; } ModulePtr q = new Module(this, name); _contents.push_back(q); return q; } ClassDefPtr Slice::Container::createClassDef(const string& name, int id, bool intf, const ClassList& bases, bool local) { ContainedList matches = _unit->findContents(thisScope() + name); for(ContainedList::const_iterator p = matches.begin(); p != matches.end(); ++p) { ClassDeclPtr decl = ClassDeclPtr::dynamicCast(*p); if(decl) { if(checkInterfaceAndLocal(name, false, intf, decl->isInterface(), local, decl->isLocal())) { continue; } return 0; } bool differsOnlyInCase = matches.front()->name() != name; ClassDefPtr def = ClassDefPtr::dynamicCast(*p); if(def) { if(differsOnlyInCase) { string msg = intf ? "interface" : "class"; msg += " definition `" + name + "' is capitalized inconsistently with its previous name: `"; msg += def->name() + "'"; _unit->error(msg); } else { if(_unit->ignRedefs()) { def->updateIncludeLevel(); return def; } string msg = "redefinition of "; msg += intf ? "interface" : "class"; msg += " `" + name + "'"; _unit->error(msg); } } else if(differsOnlyInCase) { string msg = intf ? "interface" : "class"; msg = " definition `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " name `" + matches.front()->name() + "'"; _unit->error(msg); } else { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name() + "' as "; msg += intf ? "interface" : "class"; _unit->error(msg); } return 0; } if(!nameIsLegal(name, intf ? "interface" : "class")) { return 0; } if(!checkForGlobalDef(name, intf ? "interface" : "class")) { return 0; } ClassDecl::checkBasesAreLegal(name, intf, local, bases, _unit); ClassDefPtr def = new ClassDef(this, name, id, intf, bases, local); _contents.push_back(def); for(ContainedList::const_iterator q = matches.begin(); q != matches.end(); ++q) { ClassDeclPtr decl = ClassDeclPtr::dynamicCast(*q); decl->_definition = def; } // // Implicitly create a class declaration for each class // definition. This way the code generator can rely on always // having a class declaration available for lookup. // ClassDeclPtr decl = createClassDecl(name, intf, local); def->_declaration = decl; return def; } ClassDeclPtr Slice::Container::createClassDecl(const string& name, bool intf, bool local) { ClassDefPtr def; ContainedList matches = _unit->findContents(thisScope() + name); for(ContainedList::const_iterator p = matches.begin(); p != matches.end(); ++p) { ClassDefPtr clDef = ClassDefPtr::dynamicCast(*p); if(clDef) { if(checkInterfaceAndLocal(name, true, intf, clDef->isInterface(), local, clDef->isLocal())) { assert(!def); def = clDef; continue; } return 0; } ClassDeclPtr clDecl = ClassDeclPtr::dynamicCast(*p); if(clDecl) { if(checkInterfaceAndLocal(name, false, intf, clDecl->isInterface(), local, clDecl->isLocal())) { continue; } return 0; } bool differsOnlyInCase = matches.front()->name() != name; if(differsOnlyInCase) { string msg = "class declaration `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " name `" + matches.front()->name() + "'"; _unit->error(msg); } else { string msg = "declaration of already defined `"; msg += name; msg += "' as "; msg += intf ? "interface" : "class"; _unit->error(msg); return 0; } } if(!nameIsLegal(name, intf ? "interface" : "class")) { return 0; } if(!checkForGlobalDef(name, intf ? "interface" : "class")) { return 0; } // // Multiple declarations are permissible. But if we do already // have a declaration for the class in this container, we don't // create another one. // for(ContainedList::const_iterator q = _contents.begin(); q != _contents.end(); ++q) { if((*q)->name() == name) { ClassDeclPtr decl = ClassDeclPtr::dynamicCast(*q); if(decl) { return decl; } assert(ClassDefPtr::dynamicCast(*q)); } } _unit->currentContainer(); ClassDeclPtr decl = new ClassDecl(this, name, intf, local); _contents.push_back(decl); if(def) { decl->_definition = def; } return decl; } ExceptionPtr Slice::Container::createException(const string& name, const ExceptionPtr& base, bool local, NodeType nt) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { ExceptionPtr p = ExceptionPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as exception"; _unit->error(msg); } else { string msg = "exception `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } return 0; } nameIsLegal(name, "exception"); // Don't return here -- we create the exception anyway if(nt == Real) { checkForGlobalDef(name, "exception"); // Don't return here -- we create the exception anyway } // // If this definition is non-local, base cannot be local. // if(!local && base && base->isLocal()) { _unit->error("non-local exception `" + name + "' cannot have local base exception `" + base->name() + "'"); } ExceptionPtr p = new Exception(this, name, base, local); _contents.push_back(p); return p; } StructPtr Slice::Container::createStruct(const string& name, bool local, NodeType nt) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { StructPtr p = StructPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as struct"; _unit->error(msg); } else { string msg = "struct `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } return 0; } nameIsLegal(name, "structure"); // Don't return here -- we create the struct anyway. if(nt == Real) { checkForGlobalDef(name, "structure"); // Don't return here -- we create the struct anyway. } StructPtr p = new Struct(this, name, local); _contents.push_back(p); return p; } SequencePtr Slice::Container::createSequence(const string& name, const TypePtr& type, const StringList& metaData, bool local, NodeType nt) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { SequencePtr p = SequencePtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as sequence"; _unit->error(msg); } else { string msg = "sequence `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } return 0; } nameIsLegal(name, "sequence"); // Don't return here -- we create the sequence anyway. if(nt == Real) { checkForGlobalDef(name, "sequence"); // Don't return here -- we create the sequence anyway. } // // If sequence is non-local, element type cannot be local. // if(!local && type->isLocal()) { string msg = "non-local sequence `" + name + "' cannot have local element type"; _unit->error(msg); } checkDeprecatedType(_unit, type); SequencePtr p = new Sequence(this, name, type, metaData, local); _contents.push_back(p); return p; } DictionaryPtr Slice::Container::createDictionary(const string& name, const TypePtr& keyType, const StringList& keyMetaData, const TypePtr& valueType, const StringList& valueMetaData, bool local, NodeType nt) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { DictionaryPtr p = DictionaryPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as dictionary"; _unit->error(msg); } else { string msg = "dictionary `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } return 0; } nameIsLegal(name, "dictionary"); // Don't return here -- we create the dictionary anyway. if(nt == Real) { checkForGlobalDef(name, "dictionary"); // Don't return here -- we create the dictionary anyway. } if(nt == Real) { bool containsSequence = false; if(!Dictionary::legalKeyType(keyType, containsSequence)) { _unit->error("dictionary `" + name + "' uses an illegal key type"); return 0; } if(containsSequence) { _unit->warning(Deprecated, "use of sequences in dictionary keys has been deprecated"); } } if(!local) { if(keyType->isLocal()) { string msg = "non-local dictionary `" + name + "' cannot have local key type"; _unit->error(msg); } if(valueType->isLocal()) { string msg = "non-local dictionary `" + name + "' cannot have local value type"; _unit->error(msg); } } checkDeprecatedType(_unit, valueType); DictionaryPtr p = new Dictionary(this, name, keyType, keyMetaData, valueType, valueMetaData, local); _contents.push_back(p); return p; } EnumPtr Slice::Container::createEnum(const string& name, bool local, NodeType nt) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { EnumPtr p = EnumPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as enumeration"; _unit->error(msg); } else { string msg = "enumeration `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } return 0; } nameIsLegal(name, "enumeration"); // Don't return here -- we create the enumeration anyway. if(nt == Real) { checkForGlobalDef(name, "enumeration"); // Don't return here -- we create the enumeration anyway. } EnumPtr p = new Enum(this, name, local); _contents.push_back(p); return p; } EnumeratorPtr Slice::Container::createEnumerator(const string& name) { EnumeratorPtr p = validateEnumerator(name); if(!p) { p = new Enumerator(this, name); _contents.push_back(p); } return p; } EnumeratorPtr Slice::Container::createEnumerator(const string& name, int value) { EnumeratorPtr p = validateEnumerator(name); if(!p) { p = new Enumerator(this, name, value); _contents.push_back(p); } return p; } ConstPtr Slice::Container::createConst(const string name, const TypePtr& constType, const StringList& metaData, const SyntaxTreeBasePtr& valueType, const string& value, const string& literal, NodeType nt) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { ConstPtr p = ConstPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as constant"; _unit->error(msg); } else { string msg = "constant `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } return 0; } nameIsLegal(name, "constant"); // Don't return here -- we create the constant anyway. if(nt == Real) { checkForGlobalDef(name, "constant"); // Don't return here -- we create the constant anyway. } SyntaxTreeBasePtr resolvedValueType = valueType; // // Validate the constant and its value; for enums, find enumerator // if(nt == Real && !validateConstant(name, constType, resolvedValueType, value, true)) { return 0; } ConstPtr p = new Const(this, name, constType, metaData, resolvedValueType, value, literal); _contents.push_back(p); return p; } TypeList Slice::Container::lookupType(const string& scoped, bool printError) { // // Remove whitespace. // string sc = scoped; string::size_type pos; while((pos = sc.find_first_of(" \t\r\n")) != string::npos) { sc.erase(pos, 1); } // // Check for builtin type. // for(unsigned int i = 0; i < sizeof(Builtin::builtinTable) / sizeof(const char*); ++i) { if(sc == Builtin::builtinTable[i]) { TypeList result; result.push_back(_unit->builtin(static_cast(i))); return result; } } // // Not a builtin type, try to look up a constructed type. // return lookupTypeNoBuiltin(scoped, printError); } TypeList Slice::Container::lookupTypeNoBuiltin(const string& scoped, bool printError, bool ignoreUndefined) { // // Remove whitespace. // string sc = scoped; string::size_type pos; while((pos = sc.find_first_of(" \t\r\n")) != string::npos) { sc.erase(pos, 1); } // // Absolute scoped name? // if(sc.size() >= 2 && sc[0] == ':') { return _unit->lookupTypeNoBuiltin(sc.substr(2), printError); } TypeList results; bool typeError = false; vector errors; if(sc.rfind('*') == sc.length() - 1) { // // Proxies. // ContainedList matches = _unit->findContents(thisScope() + sc.substr(0, sc.length() - 1)); for(ContainedList::const_iterator p = matches.begin(); p != matches.end(); ++p) { ClassDefPtr def = ClassDefPtr::dynamicCast(*p); if(def) { continue; // Ignore class definitions. } if(printError && matches.front()->scoped() != (thisScope() + sc)) { string msg = (*p)->kindOf() + " name `" + scoped; msg += "' is capitalized inconsistently with its previous name: `"; msg += matches.front()->scoped() + "'"; _unit->error(msg); } ClassDeclPtr cl = ClassDeclPtr::dynamicCast(*p); if(!cl) { if(printError) { string msg = "`"; msg += sc; msg += "' must be class or interface"; _unit->error(msg); } return TypeList(); } results.push_back(new Proxy(cl)); } } else { // // Non-Proxies. // ContainedList matches = _unit->findContents(thisScope() + sc); for(ContainedList::const_iterator p = matches.begin(); p != matches.end(); ++p) { ClassDefPtr def = ClassDefPtr::dynamicCast(*p); if(def) { continue; // Ignore class definitions. } if(printError && matches.front()->scoped() != (thisScope() + sc)) { string msg = (*p)->kindOf() + " name `" + scoped; msg += "' is capitalized inconsistently with its previous name: `"; msg += matches.front()->scoped() + "'"; errors.push_back(msg); } ExceptionPtr ex = ExceptionPtr::dynamicCast(*p); if(ex) { if(printError) { string msg = "`"; msg += sc; msg += "' is an exception, which cannot be used as a type"; _unit->error(msg); } return TypeList(); } TypePtr type = TypePtr::dynamicCast(*p); if(!type) { typeError = true; if(printError) { string msg = "`"; msg += sc; msg += "' is not a type"; errors.push_back(msg); } break; // Possible that correct match is higher in scope } results.push_back(type); } } if(results.empty()) { ContainedPtr contained = ContainedPtr::dynamicCast(this); if(contained) { results = contained->container()->lookupTypeNoBuiltin(sc, printError, typeError || ignoreUndefined); } else if(!typeError) { if(printError && !ignoreUndefined) { string msg = "`"; msg += sc; msg += "' is not defined"; _unit->error(msg); } return TypeList(); } } // // Do not emit errors if there was a type error but a match was found in a higher scope. // if(printError && !(typeError && !results.empty())) { for(vector::const_iterator p = errors.begin(); p != errors.end(); ++p) { _unit->error(*p); } } return results; } ContainedList Slice::Container::lookupContained(const string& scoped, bool printError) { // // Remove whitespace. // string sc = scoped; string::size_type pos; while((pos = sc.find_first_of(" \t\r\n")) != string::npos) { sc.erase(pos, 1); } // // Absolute scoped name? // if(sc.size() >= 2 && sc[0] == ':') { return _unit->lookupContained(sc.substr(2), printError); } ContainedList matches = _unit->findContents(thisScope() + sc); ContainedList results; for(ContainedList::const_iterator p = matches.begin(); p != matches.end(); ++p) { if(!ClassDefPtr::dynamicCast(*p)) // Ignore class definitions. { results.push_back(*p); if(printError && (*p)->scoped() != (thisScope() + sc)) { string msg = (*p)->kindOf() + " name `" + scoped; msg += "' is capitalized inconsistently with its previous name: `" + (*p)->scoped() + "'"; _unit->error(msg); } } } if(results.empty()) { ContainedPtr contained = ContainedPtr::dynamicCast(this); if(!contained) { if(printError) { string msg = "`"; msg += sc; msg += "' is not defined"; _unit->error(msg); } return ContainedList(); } return contained->container()->lookupContained(sc, printError); } else { return results; } } ExceptionPtr Slice::Container::lookupException(const string& scoped, bool printError) { ContainedList contained = lookupContained(scoped, printError); if(contained.empty()) { return 0; } ExceptionList exceptions; for(ContainedList::iterator p = contained.begin(); p != contained.end(); ++p) { ExceptionPtr ex = ExceptionPtr::dynamicCast(*p); if(!ex) { if(printError) { string msg = "`"; msg += scoped; msg += "' is not an exception"; _unit->error(msg); } return 0; } exceptions.push_back(ex); } assert(exceptions.size() == 1); return exceptions.front(); } UnitPtr Slice::Container::unit() const { return SyntaxTreeBase::unit(); } ModuleList Slice::Container::modules() const { ModuleList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ModulePtr q = ModulePtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } ClassList Slice::Container::classes() const { ClassList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr q = ClassDefPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } ExceptionList Slice::Container::exceptions() const { ExceptionList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ExceptionPtr q = ExceptionPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } StructList Slice::Container::structs() const { StructList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { StructPtr q = StructPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } SequenceList Slice::Container::sequences() const { SequenceList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { SequencePtr q = SequencePtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } DictionaryList Slice::Container::dictionaries() const { DictionaryList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DictionaryPtr q = DictionaryPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } EnumList Slice::Container::enums() const { EnumList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { EnumPtr q = EnumPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } EnumeratorList Slice::Container::enumerators() const { EnumeratorList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { EnumeratorPtr q = EnumeratorPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } // // Find enumerators using the old unscoped enumerators lookup // EnumeratorList Slice::Container::enumerators(const string& scoped) const { EnumeratorList result; string::size_type lastColon = scoped.rfind(':'); if(lastColon == string::npos) { // check all enclosing scopes ContainerPtr container = const_cast(this); do { EnumList enums = container->enums(); for(EnumList::iterator p = enums.begin(); p != enums.end(); ++p) { ContainedList cl = (*p)->lookupContained(scoped, false); if(!cl.empty()) { result.push_back(EnumeratorPtr::dynamicCast(cl.front())); } } ContainedPtr contained = ContainedPtr::dynamicCast(container); if(contained) { container = contained->container(); } else { container = 0; } } while(result.empty() && container); } else { // Find the referenced scope ContainerPtr container = const_cast(this); string scope = scoped.substr(0, scoped.rfind("::")); ContainedList cl = container->lookupContained(scope, false); if(!cl.empty()) { container = ContainerPtr::dynamicCast(cl.front()); if(container) { EnumList enums = container->enums(); string name = scoped.substr(lastColon + 1); for(EnumList::iterator p = enums.begin(); p != enums.end(); ++p) { ContainedList cl2 = (*p)->lookupContained(name, false); if(!cl2.empty()) { result.push_back(EnumeratorPtr::dynamicCast(cl2.front())); } } } } } return result; } ConstList Slice::Container::consts() const { ConstList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ConstPtr q = ConstPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } ContainedList Slice::Container::contents() const { return _contents; } bool Slice::Container::hasNonLocalClassDecls() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDeclPtr cl = ClassDeclPtr::dynamicCast(*p); if(cl && !cl->isLocal()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalClassDecls()) { return true; } } return false; } bool Slice::Container::hasNonLocalClassDefs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && !cl->isLocal()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalClassDefs()) { return true; } } return false; } bool Slice::Container::hasLocalClassDefsWithAsync() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && cl->isLocal()) { if(cl->hasMetaData("async-oneway")) { return true; } OperationList ol = cl->operations(); for(OperationList::const_iterator q = ol.begin(); q != ol.end(); ++q) { if((*q)->hasMetaData("async-oneway")) { return true; } } } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasLocalClassDefsWithAsync()) { return true; } } return false; } bool Slice::Container::hasNonLocalSequences() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { SequencePtr s = SequencePtr::dynamicCast(*p); if(s && !s->isLocal()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalSequences()) { return true; } } return false; } bool Slice::Container::hasNonLocalExceptions() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ExceptionPtr q = ExceptionPtr::dynamicCast(*p); if(q && !q->isLocal()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalExceptions()) { return true; } } return false; } bool Slice::Container::hasStructs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { StructPtr q = StructPtr::dynamicCast(*p); if(q) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasStructs()) { return true; } } return false; } bool Slice::Container::hasExceptions() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ExceptionPtr q = ExceptionPtr::dynamicCast(*p); if(q) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasExceptions()) { return true; } } return false; } bool Slice::Container::hasClassDecls() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if(ClassDeclPtr::dynamicCast(*p)) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasClassDecls()) { return true; } } return false; } bool Slice::Container::hasDictionaries() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DictionaryPtr d = DictionaryPtr::dynamicCast(*p); if(d) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasDictionaries()) { return true; } } return false; } bool Slice::Container::hasOnlyDictionaries(DictionaryList& dicts) const { bool ret = true; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ModulePtr m = ModulePtr::dynamicCast(*p); if(m) { bool subret = m->hasOnlyDictionaries(dicts); if(!subret && ret) { ret = false; } } DictionaryPtr d = DictionaryPtr::dynamicCast(*p); if(d && ret) { dicts.push_back(d); } else { ret = false; } } if(!ret) { dicts.clear(); } return ret; } bool Slice::Container::hasClassDefs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if(ClassDefPtr::dynamicCast(*p)) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasClassDefs()) { return true; } } return false; } bool Slice::Container::hasLocalClassDefs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && cl->isLocal()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasLocalClassDefs()) { return true; } } return false; } bool Slice::Container::hasNonLocalInterfaceDefs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && !cl->isLocal() && (cl->isInterface() || !cl->allOperations().empty())) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalInterfaceDefs()) { return true; } } return false; } bool Slice::Container::hasValueDefs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && !cl->isLocal() && !cl->isInterface()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasValueDefs()) { return true; } } return false; } bool Slice::Container::hasOnlyClassDecls() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ModulePtr m = ModulePtr::dynamicCast(*p); if(m) { if(!m->hasOnlyClassDecls()) { return false; } } else if(!ClassDeclPtr::dynamicCast(*p)) { return false; } } return true; } bool Slice::Container::hasOperations() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && cl->hasOperations()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasOperations()) { return true; } } return false; } bool Slice::Container::hasNonLocalAbstractClassDefs() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && cl->isAbstract() && !cl->isLocal()) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalAbstractClassDefs()) { return true; } } return false; } bool Slice::Container::hasNonLocalDataOnlyClasses() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr q = ClassDefPtr::dynamicCast(*p); if(q) { if(!q->isLocal() && !q->isAbstract()) { return true; } } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalDataOnlyClasses()) { return true; } } return false; } bool Slice::Container::hasOtherConstructedOrExceptions() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if(ConstructedPtr::dynamicCast(*p) && !ClassDeclPtr::dynamicCast(*p) && !ClassDefPtr::dynamicCast(*p)) { return true; } if(ExceptionPtr::dynamicCast(*p)) { return true; } if(ConstPtr::dynamicCast(*p)) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasOtherConstructedOrExceptions()) { return true; } } return false; } bool Slice::Container::hasContentsWithMetaData(const string& meta) const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if((*p)->hasMetaData(meta)) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasContentsWithMetaData(meta)) { return true; } } return false; } bool Slice::Container::hasAsyncOps() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); if(cl && !cl->isLocal()) { OperationList ops = cl->operations(); if(!ops.empty() && cl->hasMetaData("amd")) { return true; } for(OperationList::const_iterator i = ops.begin(); i != ops.end(); ++i) { OperationPtr op = *i; if(op->hasMetaData("amd")) { return true; } } } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasAsyncOps()) { return true; } } return false; } bool Slice::Container::hasNonLocalContained(Contained::ContainedType type) const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if((*p)->containedType() == type) { return true; } ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container && container->hasNonLocalContained(type)) { return true; } } return false; } string Slice::Container::thisScope() const { string s; ContainedPtr contained = ContainedPtr::dynamicCast(const_cast(this)); if(contained) { s = contained->scoped(); } s += "::"; return s; } void Slice::Container::mergeModules() { for(ContainedList::iterator p = _contents.begin(); p != _contents.end(); ++p) { ModulePtr mod1 = ModulePtr::dynamicCast(*p); if(!mod1) { continue; } DefinitionContextPtr dc1 = mod1->definitionContext(); assert(dc1); StringList metaData1 = dc1->getMetaData(); metaData1.sort(); metaData1.unique(); ContainedList::iterator q = p; ++q; while(q != _contents.end()) { ModulePtr mod2 = ModulePtr::dynamicCast(*q); if(!mod2) { ++q; continue; } if(mod1->name() != mod2->name()) { ++q; continue; } // // Compare the file metadata of the two modules being merged. // DefinitionContextPtr dc2 = mod2->definitionContext(); assert(dc2); StringList metaData2 = dc2->getMetaData(); metaData2.sort(); metaData2.unique(); if(!checkGlobalMetaData(metaData1, metaData2)) { unit()->warning(All, "file metadata mismatch for module `" + mod1->name() + "' in files " + dc1->filename() + " and " + dc2->filename()); } mod1->_contents.splice(mod1->_contents.end(), mod2->_contents); if(mod1->_comment.length() < mod2->_comment.length()) { mod1->_comment.swap(mod2->_comment); } mod1->_includeLevel = min(mod1->_includeLevel, mod2->_includeLevel); _unit->removeContent(*q); q = _contents.erase(q); } mod1->mergeModules(); } } void Slice::Container::sort() { _contents.sort(); } void Slice::Container::sortContents(bool sortFields) { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ContainerPtr container = ContainerPtr::dynamicCast(*p); if(container) { if(!sortFields) { if(StructPtr::dynamicCast(container) || ClassDefPtr::dynamicCast(container) || ExceptionPtr::dynamicCast(container)) { continue; } } // // Don't sort operation definitions, otherwise parameters are shown in the // wrong order in the synopsis. // if(!OperationPtr::dynamicCast(container)) { container->sort(); } container->sortContents(sortFields); } } } void Slice::Container::visit(ParserVisitor* visitor, bool all) { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if(all || (*p)->includeLevel() == 0) { (*p)->visit(visitor, all); } } } void Slice::Container::containerRecDependencies(set& dependencies) { for(ContainedList::iterator p = _contents.begin(); p != _contents.end(); ++p) { ConstructedPtr constructed = ConstructedPtr::dynamicCast(*p); if(constructed && dependencies.find(constructed) != dependencies.end()) { dependencies.insert(constructed); constructed->recDependencies(dependencies); } } } bool Slice::Container::checkIntroduced(const string& scoped, ContainedPtr namedThing) { if(scoped[0] == ':') // Only unscoped names introduce anything. { return true; } // // Split off first component. // string::size_type pos = scoped.find("::"); string firstComponent = pos == string::npos ? scoped : scoped.substr(0, pos); // // If we don't have a type, the thing that is introduced is the contained for // the first component. // if(namedThing == 0) { ContainedList cl = lookupContained(firstComponent, false); if(cl.empty()) { return true; // Ignore types whose creation failed previously. } namedThing = cl.front(); } else { // // For each scope, get the container until we have the container // for the first scope (which is the introduced one). // ContainerPtr c; bool first = true; while(pos != string::npos) { if(first) { c = namedThing->container(); } else { ContainedPtr contained = ContainedPtr::dynamicCast(c); if(contained) { c = contained->container(); } } first = false; if(pos != string::npos) { pos = scoped.find("::", pos + 2); } } if(ContainedPtr::dynamicCast(c)) { namedThing = ContainedPtr::dynamicCast(c); } } // // Check if the first component is in the introduced map of this scope. // map::const_iterator it = _introducedMap.find(firstComponent); if(it == _introducedMap.end()) { // // We've just introduced the first component to the current scope. // _introducedMap[firstComponent] = namedThing; // No, insert it } else { // // We've previously introduced the first component to the current scope, // check that it has not changed meaning. // if(it->second != namedThing) { // // Parameter are in its own scope. // if((ParamDeclPtr::dynamicCast(it->second) && !ParamDeclPtr::dynamicCast(namedThing)) || (!ParamDeclPtr::dynamicCast(it->second) && ParamDeclPtr::dynamicCast(namedThing))) { return true; } // // Data members are in its own scope. // if((DataMemberPtr::dynamicCast(it->second) && !DataMemberPtr::dynamicCast(namedThing)) || (!DataMemberPtr::dynamicCast(it->second) && DataMemberPtr::dynamicCast(namedThing))) { return true; } _unit->error("`" + firstComponent + "' has changed meaning"); return false; } } return true; } bool Slice::Container::nameIsLegal(const string& newName, const char* newConstruct) { ModulePtr module = ModulePtr::dynamicCast(this); // // Check whether the enclosing module has the same name. // if(module) { if(newName == module->name()) { string msg = newConstruct; msg += " name `" + newName + "' must differ from the name of its immediately enclosing module"; _unit->error(msg); return false; } string name = IceUtilInternal::toLower(newName); string thisName = IceUtilInternal::toLower(module->name()); if(name == thisName) { string msg = newConstruct; msg += " name `" + name + "' cannot differ only in capitalization from its immediately enclosing " "module name `" + module->name() + "'"; _unit->error(msg); return false; } module = ModulePtr::dynamicCast(module->container()); // Get enclosing module for test below. } // // Check whether any of the enclosing modules have the same name. // while(module) { if(newName == module->name()) { string msg = newConstruct; msg += " name `" + newName + "' must differ from the name of enclosing module `" + module->name() + "' (first defined at " + module->file() + ":" + module->line() + ")"; _unit->error(msg); return false; } string name = IceUtilInternal::toLower(newName); string thisName = IceUtilInternal::toLower(module->name()); if(name == thisName) { string msg = newConstruct; msg += " name `" + name + "' cannot differ only in capitalization from enclosing module `" + module->name() + "' (first defined at " + module->file() + ":" + module->line() + ")"; _unit->error(msg); return false; } module = ModulePtr::dynamicCast(module->container()); } return true; } bool Slice::Container::checkForGlobalDef(const string& name, const char* newConstruct) { if(dynamic_cast(this) && strcmp(newConstruct, "module")) { static const string vowels = "aeiou"; string glottalStop; if(vowels.find_first_of(newConstruct[0]) != string::npos) { glottalStop = "n"; } _unit->error("`" + name + "': a" + glottalStop + " " + newConstruct + " can be defined only at module scope"); return false; } return true; } Slice::Container::Container(const UnitPtr& unit) : SyntaxTreeBase(unit) { } bool Slice::Container::checkInterfaceAndLocal(const string& name, bool defined, bool intf, bool intfOther, bool local, bool localOther) { string definedOrDeclared; if(defined) { definedOrDeclared = "defined"; } else { definedOrDeclared = "declared"; } if(!intf && intfOther) { string msg = "class `"; msg += name; msg += "' was "; msg += definedOrDeclared; msg += " as interface"; _unit->error(msg); return false; } if(intf && !intfOther) { string msg = "interface `"; msg += name; msg += "' was "; msg += definedOrDeclared; msg += " as class"; _unit->error(msg); return false; } if(!local && localOther) { string msg = "non-local `"; msg += name; msg += "' was "; msg += definedOrDeclared; msg += " local"; _unit->error(msg); return false; } if(local && !localOther) { string msg = "local `"; msg += name; msg += "' was "; msg += definedOrDeclared; msg += " non-local"; _unit->error(msg); return false; } return true; } bool Slice::Container::checkGlobalMetaData(const StringList& m1, const StringList& m2) { // // Not all file metadata mismatches represent actual problems. We are only concerned about // the prefixes listed below (also see bug 2766). // static const char* prefixes[] = { "java:package", "python:package", 0 }; // // Collect the metadata that is unique to each list. // StringList diffs; set_symmetric_difference(m1.begin(), m1.end(), m2.begin(), m2.end(), back_inserter(diffs)); for(StringList::const_iterator p = diffs.begin(); p != diffs.end(); ++p) { for(int i = 0; prefixes[i] != 0; ++i) { if(p->find(prefixes[i]) != string::npos) { return false; } } } return true; } bool Slice::Container::validateConstant(const string& name, const TypePtr& type, SyntaxTreeBasePtr& valueType, const string& value, bool isConstant) { // // isConstant indicates whether a constant or a data member (with a default value) is // being defined. // if(!type) { return false; } const string desc = isConstant ? "constant" : "data member"; // // If valueType is a ConstPtr, it means the constant or data member being defined // refers to another constant. // const ConstPtr constant = ConstPtr::dynamicCast(valueType); // // First verify that it is legal to specify a constant or default value for the given type. // BuiltinPtr b = BuiltinPtr::dynamicCast(type); EnumPtr e = EnumPtr::dynamicCast(type); if(b) { switch(b->kind()) { case Builtin::KindBool: case Builtin::KindByte: case Builtin::KindShort: case Builtin::KindInt: case Builtin::KindLong: case Builtin::KindFloat: case Builtin::KindDouble: case Builtin::KindString: break; default: { if(isConstant) { _unit->error("constant `" + name + "' has illegal type: `" + b->kindAsString() + "'"); } else { _unit->error("default value not allowed for data member `" + name + "' of type `" + b->kindAsString() + "'"); } return false; } } } else if(!e) { if(isConstant) { _unit->error("constant `" + name + "' has illegal type"); } else { _unit->error("default value not allowed for data member `" + name + "'"); } return false; } // // Next, verify that the type of the constant or data member is compatible with the given value. // if(b) { BuiltinPtr lt; if(constant) { lt = BuiltinPtr::dynamicCast(constant->type()); } else { lt = BuiltinPtr::dynamicCast(valueType); } if(lt) { bool ok = true; switch(b->kind()) { case Builtin::KindBool: { if(lt->kind() != Builtin::KindBool) { ok = false; } break; } case Builtin::KindByte: case Builtin::KindShort: case Builtin::KindInt: case Builtin::KindLong: { switch(lt->kind()) { case Builtin::KindByte: case Builtin::KindShort: case Builtin::KindInt: case Builtin::KindLong: break; default: ok = false; break; } break; } case Builtin::KindFloat: case Builtin::KindDouble: { switch(lt->kind()) { case Builtin::KindByte: case Builtin::KindShort: case Builtin::KindInt: case Builtin::KindLong: case Builtin::KindFloat: case Builtin::KindDouble: break; default: ok = false; break; } break; } case Builtin::KindString: { if(lt->kind() != Builtin::KindString) { ok = false; } break; } case Builtin::KindObject: case Builtin::KindObjectProxy: case Builtin::KindLocalObject: case Builtin::KindValue: { assert(false); break; } } if(!ok) { string msg = "initializer of type `" + lt->kindAsString() + "' is incompatible with the type `" + b->kindAsString() + "' of " + desc + " `" + name + "'"; _unit->error(msg); return false; } } else { string msg = "type of initializer is incompatible with the type `" + b->kindAsString() + "' of " + desc + " `" + name + "'"; _unit->error(msg); return false; } switch(b->kind()) { case Builtin::KindByte: { IceUtil::Int64 l = IceUtilInternal::strToInt64(value.c_str(), 0, 0); if(l < ByteMin || l > ByteMax) { string msg = "initializer `" + value + "' for " + desc + " `" + name + "' out of range for type byte"; _unit->error(msg); return false; } break; } case Builtin::KindShort: { IceUtil::Int64 l = IceUtilInternal::strToInt64(value.c_str(), 0, 0); if(l < Int16Min || l > Int16Max) { string msg = "initializer `" + value + "' for " + desc + " `" + name + "' out of range for type short"; _unit->error(msg); return false; } break; } case Builtin::KindInt: { IceUtil::Int64 l = IceUtilInternal::strToInt64(value.c_str(), 0, 0); if(l < Int32Min || l > Int32Max) { string msg = "initializer `" + value + "' for " + desc + " `" + name + "' out of range for type int"; _unit->error(msg); return false; } break; } default: { break; } } } if(e) { if(constant) { EnumPtr ec = EnumPtr::dynamicCast(constant->type()); if(e != ec) { string msg = "type of initializer is incompatible with the type of " + desc + " `" + name + "'"; _unit->error(msg); return false; } } else { if(valueType) { EnumeratorPtr lte = EnumeratorPtr::dynamicCast(valueType); if(!lte) { string msg = "type of initializer is incompatible with the type of " + desc + " `" + name + "'"; _unit->error(msg); return false; } EnumeratorList elist = e->enumerators(); if(find(elist.begin(), elist.end(), lte) == elist.end()) { string msg = "enumerator `" + value + "' is not defined in enumeration `" + e->scoped() + "'"; _unit->error(msg); return false; } } else { // Check if value designates an enumerator of e string newVal = value; string::size_type lastColon = value.rfind(':'); if(lastColon != string::npos && lastColon + 1 < value.length()) { newVal = value.substr(0, lastColon + 1) + e->name() + "::" + value.substr(lastColon + 1); } ContainedList clist = e->lookupContained(newVal, false); if(clist.empty()) { string msg = "`" + value + "' does not designate an enumerator of `" + e->scoped() + "'"; _unit->error(msg); return false; } EnumeratorPtr lte = EnumeratorPtr::dynamicCast(clist.front()); if(lte) { valueType = lte; if(lastColon != string::npos) { _unit->warning(Deprecated, string("referencing enumerator `") + lte->name() + "' in its enumeration's enclosing scope is deprecated"); } } else { string msg = "type of initializer is incompatible with the type of " + desc + " `" + name + "'"; _unit->error(msg); return false; } } } } return true; } EnumeratorPtr Slice::Container::validateEnumerator(const string& name) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { EnumeratorPtr p = EnumeratorPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() == name) { _unit->error(string("redefinition of enumerator `") + name + "'"); } else { string msg = "enumerator `" + name + "' differs only in capitalization from "; msg += "`" + matches.front()->name() + "'"; _unit->error(msg); } } nameIsLegal(name, "enumerator"); // Ignore return value. return 0; } // ---------------------------------------------------------------------- // Module // ---------------------------------------------------------------------- Contained::ContainedType Slice::Module::containedType() const { return ContainedTypeModule; } bool Slice::Module::uses(const ContainedPtr&) const { return false; } string Slice::Module::kindOf() const { return "module"; } void Slice::Module::visit(ParserVisitor* visitor, bool all) { if(visitor->visitModuleStart(this)) { Container::visit(visitor, all); visitor->visitModuleEnd(this); } } Slice::Module::Module(const ContainerPtr& container, const string& name) : SyntaxTreeBase(container->unit()), Container(container->unit()), Contained(container, name) { } // ---------------------------------------------------------------------- // Constructed // ---------------------------------------------------------------------- bool Slice::Constructed::isLocal() const { return _local; } string Slice::Constructed::typeId() const { return scoped(); } ConstructedList Slice::Constructed::dependencies() { set resultSet; recDependencies(resultSet); #if defined(__SUNPRO_CC) && defined(_RWSTD_NO_MEMBER_TEMPLATES) // TODO: find a more usable work-around for this std lib limitation. ConstructedList result; set::iterator it = resultSet.begin(); while(it != resultSet.end()) { result.push_back(*it++); } return result; #else return ConstructedList(resultSet.begin(), resultSet.end()); #endif } Slice::Constructed::Constructed(const ContainerPtr& container, const string& name, bool local) : SyntaxTreeBase(container->unit()), Type(container->unit()), Contained(container, name), _local(local) { } // ---------------------------------------------------------------------- // ClassDecl // ---------------------------------------------------------------------- void Slice::ClassDecl::destroy() { _definition = 0; SyntaxTreeBase::destroy(); } ClassDefPtr Slice::ClassDecl::definition() const { return _definition; } bool Slice::ClassDecl::isInterface() const { return _interface; } Contained::ContainedType Slice::ClassDecl::containedType() const { return ContainedTypeClass; } bool Slice::ClassDecl::uses(const ContainedPtr&) const { return false; } bool Slice::ClassDecl::usesClasses() const { return true; } size_t Slice::ClassDecl::minWireSize() const { return 1; // At least four bytes for an instance, if the instance is marshaled as an index. } bool Slice::ClassDecl::isVariableLength() const { return true; } string Slice::ClassDecl::kindOf() const { string s; if(isLocal()) { s += "local "; } s += _interface ? "interface" : "class"; return s; } void Slice::ClassDecl::visit(ParserVisitor* visitor, bool) { visitor->visitClassDecl(this); } void Slice::ClassDecl::recDependencies(set& dependencies) { if(_definition) { _definition->containerRecDependencies(dependencies); ClassList bases = _definition->bases(); for(ClassList::iterator p = bases.begin(); p != bases.end(); ++p) { (*p)->declaration()->recDependencies(dependencies); } } } void Slice::ClassDecl::checkBasesAreLegal(const string& name, bool intf, bool local, const ClassList& bases, const UnitPtr& ut) { // // Local definitions cannot have non-local bases, and vice versa. // for(ClassList::const_iterator p = bases.begin(); p != bases.end(); ++p) { if(local != (*p)->isLocal()) { ostringstream msg; msg << (local ? "local" : "non-local") << " " << (intf ? "interface" : "class") << " `" << name << "' cannot have " << ((*p)->isLocal() ? "local" : "non-local") << " base " << ((*p)->isInterface() ? "interface" : "class") << " `" << (*p)->name() << "'"; ut->error(msg.str()); } } // // Check whether, for multiple inheritance, any of the bases define // the same operations. // if(bases.size() > 1) { // // We have multiple inheritance. Build a list of paths through the // inheritance graph, such that multiple inheritance is legal if // the union of the names defined in classes on each path are disjoint. // GraphPartitionList gpl; for(ClassList::const_iterator p = bases.begin(); p != bases.end(); ++p) { ClassList cl; gpl.push_back(cl); addPartition(gpl, gpl.rbegin(), *p); } // // We now have a list of partitions, with each partition containing // a list of class definitions. Turn the list of partitions of class // definitions into a list of sets of strings, with each // set containing the names of operations and data members defined in // the classes in each partition. // StringPartitionList spl = toStringPartitionList(gpl); // // Multiple inheritance is legal if no two partitions contain a common // name (that is, if the union of the intersections of all possible pairs // of partitions is empty). // checkPairIntersections(spl, name, ut); } } Slice::ClassDecl::ClassDecl(const ContainerPtr& container, const string& name, bool intf, bool local) : SyntaxTreeBase(container->unit()), Type(container->unit()), Contained(container, name), Constructed(container, name, local), _interface(intf) { _unit->currentContainer(); } // // Return true if the class definition cdp is on one of the class lists in gpl, false otherwise. // bool Slice::ClassDecl::isInList(const GraphPartitionList& gpl, const ClassDefPtr cdp) { for(GraphPartitionList::const_iterator i = gpl.begin(); i != gpl.end(); ++i) { if(find(i->begin(), i->end(), cdp) != i->end()) { return true; } } return false; } void Slice::ClassDecl::addPartition(GraphPartitionList& gpl, GraphPartitionList::reverse_iterator tail, const ClassDefPtr base) { // // If this base is on one of the partition lists already, do nothing. // if(isInList(gpl, base)) { return; } // // Put the current base at the end of the current partition. // tail->push_back(base); // // If the base has bases in turn, recurse, adding the first base // of base (the left-most "grandbase") to the current partition. // if(base->bases().size()) { addPartition(gpl, tail, *(base->bases().begin())); } // // If the base has multiple bases, each of the "grandbases" // except for the left-most (which we just dealt with) // adds a new partition. // if(base->bases().size() > 1) { ClassList grandBases = base->bases(); ClassList::const_iterator i = grandBases.begin(); while(++i != grandBases.end()) { ClassList cl; gpl.push_back(cl); addPartition(gpl, gpl.rbegin(), *i); } } } // // Convert the list of partitions of class definitions into a // list of lists, with each member list containing the operation // names defined by the interfaces in each partition. // Slice::ClassDecl::StringPartitionList Slice::ClassDecl::toStringPartitionList(const GraphPartitionList& gpl) { StringPartitionList spl; for(GraphPartitionList::const_iterator i = gpl.begin(); i != gpl.end(); ++i) { StringList sl; spl.push_back(sl); for(ClassList::const_iterator j = i->begin(); j != i->end(); ++j) { OperationList operations = (*j)->operations(); for(OperationList::const_iterator l = operations.begin(); l != operations.end(); ++l) { spl.rbegin()->push_back((*l)->name()); } } } return spl; } // // For all (unique) pairs of string lists, check whether an identifier in one list occurs // in the other and, if so, complain. // void Slice::ClassDecl::checkPairIntersections(const StringPartitionList& l, const string& name, const UnitPtr& ut) { set reported; for(StringPartitionList::const_iterator i = l.begin(); i != l.end(); ++i) { StringPartitionList::const_iterator cursor = i; ++cursor; for(StringPartitionList::const_iterator j = cursor; j != l.end(); ++j) { for(StringList::const_iterator s1 = i->begin(); s1 != i->end(); ++s1) { for(StringList::const_iterator s2 = j->begin(); s2 != j->end(); ++s2) { if((*s1) == (*s2) && reported.find(*s1) == reported.end()) { string msg = "ambiguous multiple inheritance: `" + name; msg += "' inherits operation `" + *s1 + "' from two or more unrelated base interfaces"; ut->error(msg); reported.insert(*s1); } else if(!CICompare()(*s1, *s2) && !CICompare()(*s2, *s1) && reported.find(*s1) == reported.end() && reported.find(*s2) == reported.end()) { string msg = "ambiguous multiple inheritance: `" + name; msg += "' inherits operations `" + *s1 + "' and `" + *s2; msg += "', which differ only in capitalization, from unrelated base interfaces"; ut->error(msg); reported.insert(*s1); reported.insert(*s2); } } } } } } // ---------------------------------------------------------------------- // ClassDef // ---------------------------------------------------------------------- void Slice::ClassDef::destroy() { _declaration = 0; _bases.clear(); Container::destroy(); } OperationPtr Slice::ClassDef::createOperation(const string& name, const TypePtr& returnType, bool optional, int tag, Operation::Mode mode) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { OperationPtr p = OperationPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() != name) { string msg = "operation `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as operation `" + name + "'"; _unit->error(msg); return 0; } // // Check whether enclosing interface/class has the same name. // if(name == this->name()) { string msg = isInterface() ? "interface" : "class"; msg += " name `" + name + "' cannot be used as operation name"; _unit->error(msg); return 0; } string newName = IceUtilInternal::toLower(name); string thisName = IceUtilInternal::toLower(this->name()); if(newName == thisName) { string msg = "operation `" + name + "' differs only in capitalization from enclosing "; msg += isInterface() ? "interface" : "class"; msg += " name `" + this->name() + "'"; _unit->error(msg); } // // Check whether any bases have defined something with the same name already. // for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { ContainedList cl; OperationList ol = (*p)->allOperations(); copy(ol.begin(), ol.end(), back_inserter(cl)); DataMemberList dml = (*p)->allDataMembers(); copy(dml.begin(), dml.end(), back_inserter(cl)); for(ContainedList::const_iterator q = cl.begin(); q != cl.end(); ++q) { if((*q)->name() == name) { string msg = "operation `" + name; msg += "' is already defined as a"; static const string vowels = "aeiou"; string kindOf = (*q)->kindOf(); if(vowels.find_first_of(kindOf[0]) != string::npos) { msg += "n"; } msg += " " + kindOf + " in a base interface or class"; _unit->error(msg); return 0; } string baseName = IceUtilInternal::toLower((*q)->name()); string newName2 = IceUtilInternal::toLower(name); if(baseName == newName2) { string msg = "operation `" + name + "' differs only in capitalization from " + (*q)->kindOf(); msg += " `" + (*q)->name() + "', which is defined in a base interface or class"; _unit->error(msg); } } } // // Non-local class/interface cannot have operation with local return type. // if(!isLocal() && returnType && returnType->isLocal()) { string msg = "non-local " + this->kindOf() + " `" + this->name() + "' cannot have operation `"; msg += name + "' with local return type"; _unit->error(msg); } if(!isInterface() && !isLocal() && !_hasOperations) { // Only warn for the first operation _unit->warning(Deprecated, "classes with operations are deprecated"); } _hasOperations = true; OperationPtr op = new Operation(this, name, returnType, optional, tag, mode); _contents.push_back(op); return op; } DataMemberPtr Slice::ClassDef::createDataMember(const string& name, const TypePtr& type, bool optional, int tag, const SyntaxTreeBasePtr& defaultValueType, const string& defaultValue, const string& defaultLiteral) { assert(!isInterface()); ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { DataMemberPtr p = DataMemberPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() != name) { string msg = "data member `" + name + "' differs only in capitalization from "; msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; _unit->error(msg); } else { string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); msg += "' as data member `" + name + "'"; _unit->error(msg); return 0; } } string newName = IceUtilInternal::toLower(name); // // Check whether any bases have defined something with the same name already. // for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { ContainedList cl; OperationList ol = (*p)->allOperations(); copy(ol.begin(), ol.end(), back_inserter(cl)); DataMemberList dml = (*p)->allDataMembers(); copy(dml.begin(), dml.end(), back_inserter(cl)); for(ContainedList::const_iterator q = cl.begin(); q != cl.end(); ++q) { if((*q)->name() == name) { string msg = "data member `" + name; msg += "' is already defined as a"; static const string vowels = "aeiou"; string kindOf = (*q)->kindOf(); if(vowels.find_first_of(kindOf[0]) != string::npos) { msg += "n"; } msg += " " + kindOf + " in a base interface or class"; _unit->error(msg); return 0; } string baseName = IceUtilInternal::toLower((*q)->name()); string newName2 = IceUtilInternal::toLower(name); if(baseName == newName2) { string msg = "data member `" + name + "' differs only in capitalization from " + (*q)->kindOf(); msg += " `" + (*q)->name() + "', which is defined in a base interface or class"; _unit->error(msg); } } } // // If data member is local, enclosing class/interface must be local. // if(!isLocal() && type->isLocal()) { string msg = "non-local " + kindOf() + "`" + this->name() + "' cannot contain local member `" + name + "'"; _unit->error(msg); } SyntaxTreeBasePtr dlt = defaultValueType; string dv = defaultValue; string dl = defaultLiteral; if(dlt || (EnumPtr::dynamicCast(type) && !dv.empty())) { // // Validate the default value. // if(!validateConstant(name, type, dlt, dv, false)) { // // Create the data member anyway, just without the default value. // dlt = 0; dv.clear(); dl.clear(); } } if(optional) { // // Validate the tag. // DataMemberList dml = dataMembers(); for(DataMemberList::iterator q = dml.begin(); q != dml.end(); ++q) { if((*q)->optional() && tag == (*q)->tag()) { string msg = "tag for optional data member `" + name + "' is already in use"; _unit->error(msg); break; } } } checkDeprecatedType(_unit, type); _hasDataMembers = true; DataMemberPtr member = new DataMember(this, name, type, optional, tag, dlt, dv, dl); _contents.push_back(member); return member; } ClassDeclPtr Slice::ClassDef::declaration() const { return _declaration; } ClassList Slice::ClassDef::bases() const { return _bases; } ClassList Slice::ClassDef::allBases() const { ClassList result = _bases; result.sort(); result.unique(); for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { ClassList li = (*p)->allBases(); result.merge(li); result.unique(); } return result; } OperationList Slice::ClassDef::operations() const { OperationList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { OperationPtr q = OperationPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } OperationList Slice::ClassDef::allOperations() const { OperationList result; for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { OperationList li = (*p)->allOperations(); for(OperationList::const_iterator q = li.begin(); q != li.end(); ++q) { if(find(result.begin(), result.end(), *q) == result.end()) { result.push_back(*q); } } } OperationList li = operations(); for(OperationList::const_iterator q = li.begin(); q != li.end(); ++q) { if(find(result.begin(), result.end(), *q) == result.end()) { result.push_back(*q); } } return result; } DataMemberList Slice::ClassDef::dataMembers() const { DataMemberList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } DataMemberList Slice::ClassDef::orderedOptionalDataMembers() const { return filterOrderedOptionalDataMembers(dataMembers()); } // // Return the data members of this class and its parent classes, in base-to-derived order. // DataMemberList Slice::ClassDef::allDataMembers() const { DataMemberList result; // // Check if we have a base class. If so, recursively // get the data members of the base(s). // if(!_bases.empty() && !_bases.front()->isInterface()) { result = _bases.front()->allDataMembers(); } // // Append this class's data members. // DataMemberList myMembers = dataMembers(); result.splice(result.end(), myMembers); return result; } DataMemberList Slice::ClassDef::classDataMembers() const { DataMemberList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { BuiltinPtr builtin = BuiltinPtr::dynamicCast(q->type()); if((builtin && builtin->kind() == Builtin::KindObject) || (builtin && builtin->kind() == Builtin::KindValue) || ClassDeclPtr::dynamicCast(q->type())) { result.push_back(q); } } } return result; } // // Return the class data members of this class and its parent classes, in base-to-derived order. // DataMemberList Slice::ClassDef::allClassDataMembers() const { DataMemberList result; // // Check if we have a base class. If so, recursively // get the class data members of the base(s). // if(!_bases.empty() && !_bases.front()->isInterface()) { result = _bases.front()->allClassDataMembers(); } // // Append this class's class members. // DataMemberList myMembers = classDataMembers(); result.splice(result.end(), myMembers); return result; } bool Slice::ClassDef::canBeCyclic() const { if(!_bases.empty() && !_bases.front()->isInterface() && _bases.front()->canBeCyclic()) { return true; } DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { if((*i)->type()->usesClasses()) { return true; } } return false; } bool Slice::ClassDef::isAbstract() const { if(isInterface() || _bases.size() > 1) // Is this an interface, or does it derive from interfaces? { return true; } if(!_bases.empty() && _bases.front()->isAbstract()) { return true; } for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { if(OperationPtr::dynamicCast(*p)) { return true; } } return false; } bool Slice::ClassDef::isInterface() const { return _interface; } bool Slice::ClassDef::isA(const string& id) const { if(id == _scoped) { return true; } for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { if((*p)->isA(id)) { return true; } } return false; } bool Slice::ClassDef::isLocal() const { return _local; } bool Slice::ClassDef::hasDataMembers() const { return _hasDataMembers; } bool Slice::ClassDef::hasOperations() const { return _hasOperations; } bool Slice::ClassDef::hasDefaultValues() const { DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { if((*i)->defaultValueType()) { return true; } } return false; } bool Slice::ClassDef::inheritsMetaData(const string& meta) const { for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { if((*p)->hasMetaData(meta) || (*p)->inheritsMetaData(meta)) { return true; } } return false; } bool Slice::ClassDef::hasBaseDataMembers() const { if(!_bases.empty() && !_bases.front()->isInterface()) { return !_bases.front()->allDataMembers().empty(); } return false; } Contained::ContainedType Slice::ClassDef::containedType() const { return ContainedTypeClass; } bool Slice::ClassDef::uses(const ContainedPtr&) const { // No uses() implementation here. DataMember and Operation have // their own uses(). return false; } string Slice::ClassDef::kindOf() const { string s; if(isLocal()) { s += "local "; } s += isInterface() ? "interface" : "class"; return s; } void Slice::ClassDef::visit(ParserVisitor* visitor, bool all) { if(visitor->visitClassDefStart(this)) { Container::visit(visitor, all); visitor->visitClassDefEnd(this); } } int Slice::ClassDef::compactId() const { return _compactId; } bool Slice::ClassDef::isDelegate() const { return isLocal() && isInterface() && hasMetaData("delegate") && allOperations().size() == 1; } Slice::ClassDef::ClassDef(const ContainerPtr& container, const string& name, int id, bool intf, const ClassList& bases, bool local) : SyntaxTreeBase(container->unit()), Container(container->unit()), Contained(container, name), _interface(intf), _hasDataMembers(false), _hasOperations(false), _bases(bases), _local(local), _compactId(id) { if(!local && !intf) { for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { if((*p)->isInterface()) { _unit->warning(Deprecated, "classes implementing interfaces are deprecated"); break; } } } // // First element of bases may be a class, all others must be // interfaces. // #ifndef NDEBUG for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) { assert(p == _bases.begin() || (*p)->isInterface()); } #endif if(_compactId >= 0) { _unit->addTypeId(_compactId, scoped()); } } // ---------------------------------------------------------------------- // Proxy // ---------------------------------------------------------------------- bool Slice::Proxy::isLocal() const { return _classDecl->isLocal(); } string Slice::Proxy::typeId() const { return _classDecl->scoped(); } bool Slice::Proxy::usesClasses() const { return false; } size_t Slice::Proxy::minWireSize() const { return 2; // At least two bytes for a nil proxy (empty name and empty category strings). } bool Slice::Proxy::isVariableLength() const { return true; } ClassDeclPtr Slice::Proxy::_class() const { return _classDecl; } Slice::Proxy::Proxy(const ClassDeclPtr& cl) : SyntaxTreeBase(cl->unit(), cl->definitionContext()), Type(cl->unit()), _classDecl(cl) { } // ---------------------------------------------------------------------- // Exception // ---------------------------------------------------------------------- void Slice::Exception::destroy() { _base = 0; Container::destroy(); } DataMemberPtr Slice::Exception::createDataMember(const string& name, const TypePtr& type, bool optional, int tag, const SyntaxTreeBasePtr& defaultValueType, const string& defaultValue, const string& defaultLiteral) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { DataMemberPtr p = DataMemberPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() != name) { string msg = "exception member `" + name + "' differs only in capitalization from "; msg += "exception member `" + matches.front()->name() + "'"; _unit->error(msg); } else { string msg = "redefinition of exception member `" + name + "'"; _unit->error(msg); return 0; } } string newName = IceUtilInternal::toLower(name); // // Check whether any bases have defined a member with the same name already. // ExceptionList bl = allBases(); for(ExceptionList::const_iterator q = bl.begin(); q != bl.end(); ++q) { ContainedList cl; DataMemberList dml = (*q)->dataMembers(); copy(dml.begin(), dml.end(), back_inserter(cl)); for(ContainedList::const_iterator r = cl.begin(); r != cl.end(); ++r) { if((*r)->name() == name) { string msg = "exception member `" + name + "' is already defined in a base exception"; _unit->error(msg); return 0; } string baseName = IceUtilInternal::toLower((*r)->name()); string newName2 = IceUtilInternal::toLower(name); if(baseName == newName2) { string msg = "exception member `" + name + "' differs only in capitalization from exception member `"; msg += (*r)->name() + "', which is defined in a base exception"; _unit->error(msg); } } } // // If data member is local, enclosing class/interface must be local. // if(!isLocal() && type->isLocal()) { string msg = "non-local " + kindOf() + "`" + this->name() + "' cannot contain local member `" + name + "'"; _unit->error(msg); } SyntaxTreeBasePtr dlt = defaultValueType; string dv = defaultValue; string dl = defaultLiteral; if(dlt || (EnumPtr::dynamicCast(type) && !dv.empty())) { // // Validate the default value. // if(!validateConstant(name, type, dlt, dv, false)) { // // Create the data member anyway, just without the default value. // dlt = 0; dv.clear(); dl.clear(); } } if(optional) { // // Validate the tag. // DataMemberList dml = dataMembers(); for(DataMemberList::iterator q = dml.begin(); q != dml.end(); ++q) { if((*q)->optional() && tag == (*q)->tag()) { string msg = "tag for optional data member `" + name + "' is already in use"; _unit->error(msg); break; } } } checkDeprecatedType(_unit, type); DataMemberPtr p = new DataMember(this, name, type, optional, tag, dlt, dv, dl); _contents.push_back(p); return p; } DataMemberList Slice::Exception::dataMembers() const { DataMemberList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } DataMemberList Slice::Exception::orderedOptionalDataMembers() const { return filterOrderedOptionalDataMembers(dataMembers()); } // // Return the data members of this exception and its parent exceptions, in base-to-derived order. // DataMemberList Slice::Exception::allDataMembers() const { DataMemberList result; // // Check if we have a base exception. If so, recursively // get the data members of the base exception(s). // if(base()) { result = base()->allDataMembers(); } // // Append this exceptions's data members. // DataMemberList myMembers = dataMembers(); result.splice(result.end(), myMembers); return result; } DataMemberList Slice::Exception::classDataMembers() const { DataMemberList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { BuiltinPtr builtin = BuiltinPtr::dynamicCast(q->type()); if((builtin && builtin->kind() == Builtin::KindObject) || (builtin && builtin->kind() == Builtin::KindValue) || ClassDeclPtr::dynamicCast(q->type())) { result.push_back(q); } } } return result; } // // Return the class data members of this exception and its parent exceptions, in base-to-derived order. // DataMemberList Slice::Exception::allClassDataMembers() const { DataMemberList result; // // Check if we have a base exception. If so, recursively // get the class data members of the base exception(s). // if(base()) { result = base()->allClassDataMembers(); } // // Append this exceptions's class data members. // DataMemberList myMembers = classDataMembers(); result.splice(result.end(), myMembers); return result; } ExceptionPtr Slice::Exception::base() const { return _base; } ExceptionList Slice::Exception::allBases() const { ExceptionList result; if(_base) { result = _base->allBases(); result.push_front(_base); } return result; } bool Slice::Exception::isBaseOf(const ExceptionPtr& other) const { if(this->scoped() == other->scoped()) { return false; } ExceptionList bases = other->allBases(); for(ExceptionList::const_iterator i = bases.begin(); i != bases.end(); ++i) { if((*i)->scoped() == scoped()) { return true; } } return false; } bool Slice::Exception::isLocal() const { return _local; } Contained::ContainedType Slice::Exception::containedType() const { return ContainedTypeException; } bool Slice::Exception::uses(const ContainedPtr&) const { // No uses() implementation here. DataMember has its own uses(). return false; } bool Slice::Exception::usesClasses(bool includeOptional) const { DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { if((*i)->type()->usesClasses() && (includeOptional || !(*i)->optional())) { return true; } } if(_base) { return _base->usesClasses(includeOptional); } return false; } bool Slice::Exception::hasDefaultValues() const { DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { if((*i)->defaultValueType()) { return true; } } return false; } bool Slice::Exception::inheritsMetaData(const string& meta) const { if(_base && (_base->hasMetaData(meta) || _base->inheritsMetaData(meta))) { return true; } return false; } bool Slice::Exception::hasBaseDataMembers() const { return _base && !_base->allDataMembers().empty(); } string Slice::Exception::kindOf() const { return "exception"; } void Slice::Exception::visit(ParserVisitor* visitor, bool all) { if(visitor->visitExceptionStart(this)) { Container::visit(visitor, all); visitor->visitExceptionEnd(this); } } Slice::Exception::Exception(const ContainerPtr& container, const string& name, const ExceptionPtr& base, bool local) : SyntaxTreeBase(container->unit()), Container(container->unit()), Contained(container, name), _base(base), _local(local) { } // ---------------------------------------------------------------------- // Struct // ---------------------------------------------------------------------- DataMemberPtr Slice::Struct::createDataMember(const string& name, const TypePtr& type, bool optional, int tag, const SyntaxTreeBasePtr& defaultValueType, const string& defaultValue, const string& defaultLiteral) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { DataMemberPtr p = DataMemberPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() != name) { string msg = "member `" + name + "' differs only in capitalization from "; msg += "member `" + matches.front()->name() + "'"; _unit->error(msg); } else { string msg = "redefinition of struct member `" + name + "'"; _unit->error(msg); return 0; } } // // Structures cannot contain themselves. // if(type.get() == this) { string msg = "struct `"; msg += this->name(); msg += "' cannot contain itself"; _unit->error(msg); return 0; } // // If data member is local, enclosing class/interface must be local. // if(!isLocal() && type->isLocal()) { string msg = "non-local " + kindOf() + "`" + this->name() + "' cannot contain local member `" + name + "'"; _unit->error(msg); } SyntaxTreeBasePtr dlt = defaultValueType; string dv = defaultValue; string dl = defaultLiteral; if(dlt || (EnumPtr::dynamicCast(type) && !dv.empty())) { // // Validate the default value. // if(!validateConstant(name, type, dlt, dv, false)) { // // Create the data member anyway, just without the default value. // dlt = 0; dv.clear(); dl.clear(); } } if(optional) { // // Validate the tag. // DataMemberList dml = dataMembers(); for(DataMemberList::iterator q = dml.begin(); q != dml.end(); ++q) { if((*q)->optional() && tag == (*q)->tag()) { string msg = "tag for optional data member `" + name + "' is already in use"; _unit->error(msg); break; } } } checkDeprecatedType(_unit, type); DataMemberPtr p = new DataMember(this, name, type, optional, tag, dlt, dv, dl); _contents.push_back(p); return p; } DataMemberList Slice::Struct::dataMembers() const { DataMemberList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } DataMemberList Slice::Struct::classDataMembers() const { DataMemberList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { BuiltinPtr builtin = BuiltinPtr::dynamicCast(q->type()); if((builtin && builtin->kind() == Builtin::KindObject) || (builtin && builtin->kind() == Builtin::KindValue) || ClassDeclPtr::dynamicCast(q->type())) { result.push_back(q); } } } return result; } Contained::ContainedType Slice::Struct::containedType() const { return ContainedTypeStruct; } bool Slice::Struct::uses(const ContainedPtr&) const { return false; } bool Slice::Struct::usesClasses() const { for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { DataMemberPtr q = DataMemberPtr::dynamicCast(*p); if(q) { TypePtr t = q->type(); if(t->usesClasses()) { return true; } } } return false; } size_t Slice::Struct::minWireSize() const { // // At least the sum of the minimum member sizes. // size_t sz = 0; DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { sz += (*i)->type()->minWireSize(); } return sz; } bool Slice::Struct::isVariableLength() const { DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { if((*i)->type()->isVariableLength()) { return true; } } return false; } bool Slice::Struct::hasDefaultValues() const { DataMemberList dml = dataMembers(); for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) { if((*i)->defaultValueType()) { return true; } } return false; } string Slice::Struct::kindOf() const { return "struct"; } void Slice::Struct::visit(ParserVisitor* visitor, bool all) { if(visitor->visitStructStart(this)) { Container::visit(visitor, all); visitor->visitStructEnd(this); } } void Slice::Struct::recDependencies(set& dependencies) { containerRecDependencies(dependencies); } Slice::Struct::Struct(const ContainerPtr& container, const string& name, bool local) : SyntaxTreeBase(container->unit()), Container(container->unit()), Type(container->unit()), Contained(container, name), Constructed(container, name, local) { } // ---------------------------------------------------------------------- // Sequence // ---------------------------------------------------------------------- TypePtr Slice::Sequence::type() const { return _type; } StringList Slice::Sequence::typeMetaData() const { return _typeMetaData; } Contained::ContainedType Slice::Sequence::containedType() const { return ContainedTypeSequence; } bool Slice::Sequence::uses(const ContainedPtr& contained) const { ContainedPtr contained2 = ContainedPtr::dynamicCast(_type); if(contained2 && contained2 == contained) { return true; } return false; } bool Slice::Sequence::usesClasses() const { return _type->usesClasses(); } size_t Slice::Sequence::minWireSize() const { return 1; // An empty sequence. } bool Slice::Sequence::isVariableLength() const { return true; } string Slice::Sequence::kindOf() const { return "sequence"; } void Slice::Sequence::visit(ParserVisitor* visitor, bool) { visitor->visitSequence(this); } void Slice::Sequence::recDependencies(set& dependencies) { ConstructedPtr constructed = ConstructedPtr::dynamicCast(_type); if(constructed && dependencies.find(constructed) != dependencies.end()) { dependencies.insert(constructed); constructed->recDependencies(dependencies); } } Slice::Sequence::Sequence(const ContainerPtr& container, const string& name, const TypePtr& type, const StringList& typeMetaData, bool local) : SyntaxTreeBase(container->unit()), Type(container->unit()), Contained(container, name), Constructed(container, name, local), _type(type), _typeMetaData(typeMetaData) { } // ---------------------------------------------------------------------- // Dictionary // ---------------------------------------------------------------------- TypePtr Slice::Dictionary::keyType() const { return _keyType; } TypePtr Slice::Dictionary::valueType() const { return _valueType; } StringList Slice::Dictionary::keyMetaData() const { return _keyMetaData; } StringList Slice::Dictionary::valueMetaData() const { return _valueMetaData; } Contained::ContainedType Slice::Dictionary::containedType() const { return ContainedTypeDictionary; } bool Slice::Dictionary::uses(const ContainedPtr& contained) const { { ContainedPtr contained2 = ContainedPtr::dynamicCast(_keyType); if(contained2 && contained2 == contained) { return true; } } { ContainedPtr contained2 = ContainedPtr::dynamicCast(_valueType); if(contained2 && contained2 == contained) { return true; } } return false; } bool Slice::Dictionary::usesClasses() const { return _valueType->usesClasses(); } size_t Slice::Dictionary::minWireSize() const { return 1; // An empty dictionary. } bool Slice::Dictionary::isVariableLength() const { return true; } string Slice::Dictionary::kindOf() const { return "dictionary"; } void Slice::Dictionary::visit(ParserVisitor* visitor, bool) { visitor->visitDictionary(this); } void Slice::Dictionary::recDependencies(set& dependencies) { { ConstructedPtr constructed = ConstructedPtr::dynamicCast(_keyType); if(constructed && dependencies.find(constructed) != dependencies.end()) { dependencies.insert(constructed); constructed->recDependencies(dependencies); } } { ConstructedPtr constructed = ConstructedPtr::dynamicCast(_valueType); if(constructed && dependencies.find(constructed) != dependencies.end()) { dependencies.insert(constructed); constructed->recDependencies(dependencies); } } } // // Check that the key type of a dictionary is legal. Legal types are // integral types, string, and sequences and structs containing only // other legal key types. // // Note: Allowing sequences in dictionary keys has been deprecated as // of Ice 3.3.0. // bool Slice::Dictionary::legalKeyType(const TypePtr& type, bool& containsSequence) { BuiltinPtr bp = BuiltinPtr::dynamicCast(type); if(bp) { switch(bp->kind()) { case Builtin::KindByte: case Builtin::KindBool: case Builtin::KindShort: case Builtin::KindInt: case Builtin::KindLong: case Builtin::KindString: { return true; break; } case Builtin::KindFloat: case Builtin::KindDouble: case Builtin::KindObject: case Builtin::KindObjectProxy: case Builtin::KindLocalObject: case Builtin::KindValue: { return false; break; } } } EnumPtr ep = EnumPtr::dynamicCast(type); if(ep) { return true; } SequencePtr seqp = SequencePtr::dynamicCast(type); if(seqp) { containsSequence = true; if(legalKeyType(seqp->type(), containsSequence)) { return true; } } StructPtr strp = StructPtr::dynamicCast(type); if(strp) { DataMemberList dml = strp->dataMembers(); for(DataMemberList::const_iterator mem = dml.begin(); mem != dml.end(); ++mem) { if(!legalKeyType((*mem)->type(), containsSequence)) { return false; } } return true; } return false; } Slice::Dictionary::Dictionary(const ContainerPtr& container, const string& name, const TypePtr& keyType, const StringList& keyMetaData, const TypePtr& valueType, const StringList& valueMetaData, bool local) : SyntaxTreeBase(container->unit()), Type(container->unit()), Contained(container, name), Constructed(container, name, local), _keyType(keyType), _valueType(valueType), _keyMetaData(keyMetaData), _valueMetaData(valueMetaData) { } // ---------------------------------------------------------------------- // Enum // ---------------------------------------------------------------------- void Slice::Enum::destroy() { SyntaxTreeBase::destroy(); } bool Slice::Enum::explicitValue() const { return _explicitValue; } int Slice::Enum::minValue() const { return static_cast(_minValue); } int Slice::Enum::maxValue() const { return static_cast(_maxValue); } Contained::ContainedType Slice::Enum::containedType() const { return ContainedTypeEnum; } bool Slice::Enum::uses(const ContainedPtr&) const { return false; } bool Slice::Enum::usesClasses() const { return false; } size_t Slice::Enum::minWireSize() const { return 1; } bool Slice::Enum::isVariableLength() const { return true; } string Slice::Enum::kindOf() const { return "enumeration"; } void Slice::Enum::visit(ParserVisitor* visitor, bool) { visitor->visitEnum(this); } void Slice::Enum::recDependencies(set&) { // An Enum does not have any dependencies. } Slice::Enum::Enum(const ContainerPtr& container, const string& name, bool local) : SyntaxTreeBase(container->unit()), Container(container->unit()), Type(container->unit()), Contained(container, name), Constructed(container, name, local), _explicitValue(false), _minValue(Int32Max), _maxValue(0), _lastValue(-1) { } int Slice::Enum::newEnumerator(const EnumeratorPtr& p) { if(p->explicitValue()) { _explicitValue = true; _lastValue = p->value(); if(_lastValue < 0) { string msg = "value for enumerator `" + p->name() + "' is out of range"; _unit->error(msg); } } else { if(_lastValue == Int32Max) { string msg = "value for enumerator `" + p->name() + "' is out of range"; _unit->error(msg); } else { // // If the enumerator was not assigned an explicit value, we automatically assign // it one more than the previous enumerator. // ++_lastValue; } } bool checkForDuplicates = true; if(_lastValue > _maxValue) { _maxValue = _lastValue; checkForDuplicates = false; } if(_lastValue < _minValue) { _minValue = _lastValue; checkForDuplicates = false; } if(checkForDuplicates) { EnumeratorList enl = enumerators(); for(EnumeratorList::iterator q = enl.begin(); q != enl.end(); ++q) { EnumeratorPtr& r = *q; if(r != p && r->value() == _lastValue) { _unit->error(string("enumerator `") + p->name() + "' has the same value as enumerator `" + r->name() + "'"); } } } return _lastValue; } // ---------------------------------------------------------------------- // Enumerator // ---------------------------------------------------------------------- EnumPtr Slice::Enumerator::type() const { return EnumPtr::dynamicCast(container()); } Contained::ContainedType Slice::Enumerator::containedType() const { return ContainedTypeEnumerator; } bool Slice::Enumerator::uses(const ContainedPtr&) const { return false; } string Slice::Enumerator::kindOf() const { return "enumerator"; } bool Slice::Enumerator::explicitValue() const { return _explicitValue; } int Slice::Enumerator::value() const { return _value; } Slice::Enumerator::Enumerator(const ContainerPtr& container, const string& name) : SyntaxTreeBase(container->unit()), Contained(container, name), _explicitValue(false), _value(-1) { _value = EnumPtr::dynamicCast(container)->newEnumerator(this); } Slice::Enumerator::Enumerator(const ContainerPtr& container, const string& name, int value) : SyntaxTreeBase(container->unit()), Contained(container, name), _explicitValue(true), _value(value) { EnumPtr::dynamicCast(container)->newEnumerator(this); } // ---------------------------------------------------------------------- // Const // ---------------------------------------------------------------------- TypePtr Slice::Const::type() const { return _type; } StringList Slice::Const::typeMetaData() const { return _typeMetaData; } SyntaxTreeBasePtr Slice::Const::valueType() const { return _valueType; } string Slice::Const::value() const { return _value; } string Slice::Const::literal() const { return _literal; } Contained::ContainedType Slice::Const::containedType() const { return ContainedTypeConstant; } bool Slice::Const::uses(const ContainedPtr& contained) const { ContainedPtr contained2 = ContainedPtr::dynamicCast(_type); return (contained2 && contained2 == contained); } string Slice::Const::kindOf() const { return "constant"; } void Slice::Const::visit(ParserVisitor* visitor, bool) { visitor->visitConst(this); } Slice::Const::Const(const ContainerPtr& container, const string& name, const TypePtr& type, const StringList& typeMetaData, const SyntaxTreeBasePtr& valueType, const string& value, const string& literal) : SyntaxTreeBase(container->unit()), Contained(container, name), _type(type), _typeMetaData(typeMetaData), _valueType(valueType), _value(value), _literal(literal) { if(valueType == 0) { cerr << "const " << name << " created with null valueType" << endl; } } // ---------------------------------------------------------------------- // Operation // ---------------------------------------------------------------------- TypePtr Slice::Operation::returnType() const { return _returnType; } bool Slice::Operation::returnIsOptional() const { return _returnIsOptional; } int Slice::Operation::returnTag() const { return _returnTag; } Operation::Mode Slice::Operation::mode() const { return _mode; } Operation::Mode Slice::Operation::sendMode() const { if(_mode == Operation::Idempotent && hasMetaData("nonmutating")) { return Operation::Nonmutating; } else { return _mode; } } bool Slice::Operation::hasMarshaledResult() const { ClassDefPtr cl = ClassDefPtr::dynamicCast(container()); assert(cl); if(cl->hasMetaData("marshaled-result") || hasMetaData("marshaled-result")) { if(returnType() && isMutableAfterReturnType(returnType())) { return true; } for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p); if(q->isOutParam() && isMutableAfterReturnType(q->type())) { return true; } } } return false; } ParamDeclPtr Slice::Operation::createParamDecl(const string& name, const TypePtr& type, bool isOutParam, bool optional, int tag) { ContainedList matches = _unit->findContents(thisScope() + name); if(!matches.empty()) { ParamDeclPtr p = ParamDeclPtr::dynamicCast(matches.front()); if(p) { if(_unit->ignRedefs()) { p->updateIncludeLevel(); return p; } } if(matches.front()->name() != name) { string msg = "parameter `" + name + "' differs only in capitalization from "; msg += "parameter `" + matches.front()->name() + "'"; _unit->error(msg); } else { string msg = "redefinition of parameter `" + name + "'"; _unit->error(msg); return 0; } } string newName = IceUtilInternal::toLower(name); string thisName = IceUtilInternal::toLower(this->name()); // // Check that in parameters don't follow out parameters. // if(!_contents.empty()) { ParamDeclPtr p = ParamDeclPtr::dynamicCast(_contents.back()); assert(p); if(p->isOutParam() && !isOutParam) { _unit->error("`" + name + "': in parameters cannot follow out parameters"); } } // // Non-local class/interface cannot have operation with local parameters. // ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container()); assert(cl); if(type->isLocal() && !cl->isLocal()) { string msg = "non-local " + cl->kindOf() + " `" + cl->name() + "' cannot have local parameter `"; msg += name + "' in operation `" + this->name() + "'"; _unit->error(msg); } // // Issue a warning for a deprecated parameter type. // checkDeprecatedType(_unit, type); if(optional) { // // Check for a duplicate tag. // const string msg = "tag for optional parameter `" + name + "' is already in use"; if(_returnIsOptional && tag == _returnTag) { _unit->error(msg); } else { ParamDeclList params = parameters(); for(ParamDeclList::const_iterator p = params.begin(); p != params.end(); ++p) { if((*p)->optional() && (*p)->tag() == tag) { _unit->error(msg); break; } } } } ParamDeclPtr p = new ParamDecl(this, name, type, isOutParam, optional, tag); _contents.push_back(p); return p; } ParamDeclList Slice::Operation::parameters() const { ParamDeclList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p); if(q) { result.push_back(q); } } return result; } ParamDeclList Slice::Operation::inParameters() const { ParamDeclList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p); if(q && !q->isOutParam()) { result.push_back(q); } } return result; } void Slice::Operation::inParameters(ParamDeclList& required, ParamDeclList& optional) const { const ParamDeclList params = inParameters(); for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli) { if((*pli)->optional()) { optional.push_back(*pli); } else { required.push_back(*pli); } } sortOptionalParameters(optional); } ParamDeclList Slice::Operation::outParameters() const { ParamDeclList result; for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) { ParamDeclPtr q = ParamDeclPtr::dynamicCast(*p); if(q && q->isOutParam()) { result.push_back(q); } } return result; } void Slice::Operation::outParameters(ParamDeclList& required, ParamDeclList& optional) const { const ParamDeclList params = outParameters(); for(ParamDeclList::const_iterator pli = params.begin(); pli != params.end(); ++pli) { if((*pli)->optional()) { optional.push_back(*pli); } else { required.push_back(*pli); } } sortOptionalParameters(optional); } ExceptionList Slice::Operation::throws() const { return _throws; } void Slice::Operation::setExceptionList(const ExceptionList& el) { _throws = el; // // Check that no exception occurs more than once in the throws clause. // ExceptionList uniqueExceptions = el; uniqueExceptions.sort(); uniqueExceptions.unique(); if(uniqueExceptions.size() != el.size()) { // // At least one exception appears twice. // ExceptionList tmp = el; tmp.sort(); ExceptionList duplicates; set_difference(tmp.begin(), tmp.end(), uniqueExceptions.begin(), uniqueExceptions.end(), back_inserter(duplicates)); string msg = "operation `" + name() + "' has a throws clause with "; if(duplicates.size() == 1) { msg += "a "; } msg += "duplicate exception"; if(duplicates.size() > 1) { msg += "s"; } ExceptionList::const_iterator i = duplicates.begin(); msg += ": `" + (*i)->name() + "'"; for(i = ++i; i != duplicates.end(); ++i) { msg += ", `" + (*i)->name() + "'"; } _unit->error(msg); } // // If the interface is non-local, no local exception can be thrown. // ClassDefPtr cl = ClassDefPtr::dynamicCast(container()); assert(cl); if(!cl->isLocal()) { for(ExceptionList::const_iterator ep = el.begin(); ep != el.end(); ++ep) { if((*ep)->isLocal()) { string msg = "non-local " + cl->kindOf() + " `" + cl->name() + "' cannot have operation `"; msg += name() + "' throwing local exception `" + (*ep)->name() + "'"; _unit->error(msg); } } } } Contained::ContainedType Slice::Operation::containedType() const { return ContainedTypeOperation; } bool Slice::Operation::uses(const ContainedPtr& contained) const { { ContainedPtr contained2 = ContainedPtr::dynamicCast(_returnType); if(contained2 && contained2 == contained) { return true; } } for(ExceptionList::const_iterator q = _throws.begin(); q != _throws.end(); ++q) { ContainedPtr contained2 = ContainedPtr::dynamicCast(*q); if(contained2 && contained2 == contained) { return true; } } return false; } bool Slice::Operation::sendsClasses(bool includeOptional) const { ParamDeclList pdl = parameters(); for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) { if(!(*i)->isOutParam() && (*i)->type()->usesClasses() && (includeOptional || !(*i)->optional())) { return true; } } return false; } bool Slice::Operation::returnsClasses(bool includeOptional) const { TypePtr t = returnType(); if(t && t->usesClasses() && (includeOptional || !_returnIsOptional)) { return true; } ParamDeclList pdl = parameters(); for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) { if((*i)->isOutParam() && (*i)->type()->usesClasses() && (includeOptional || !(*i)->optional())) { return true; } } return false; } bool Slice::Operation::returnsData() const { TypePtr t = returnType(); if(t) { return true; } ParamDeclList pdl = parameters(); for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) { if((*i)->isOutParam()) { return true; } } if(!throws().empty()) { return true; } return false; } bool Slice::Operation::returnsMultipleValues() const { size_t count = outParameters().size(); if(returnType()) { ++count; } return count > 1; } bool Slice::Operation::sendsOptionals() const { ParamDeclList pdl = inParameters(); for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) { if((*i)->optional()) { return true; } } return false; } int Slice::Operation::attributes() const { string freezeMD; if(!findMetaData("freeze:", freezeMD)) { ClassDefPtr classDef = ClassDefPtr::dynamicCast(container()); assert(classDef != 0); classDef->findMetaData("freeze:", freezeMD); } if(freezeMD != "") { int result = 0; freezeMD = freezeMD.substr(strlen("freeze:")); int i = 0; while(i < 2) { if(freezeMD.find(readWriteAttribute[i]) == 0) { result = i; freezeMD = freezeMD.substr(readWriteAttribute[i].size()); break; // while } i++; } if(i == 2) { _unit->warning(InvalidMetaData, "invalid freeze metadata for operation"); } else { if(freezeMD.size() == 0) { freezeMD = (result == 0) ? ":supports" : ":required"; } // // Remove ":" // freezeMD = freezeMD.substr(1); i = 0; while(i < 4) { if(freezeMD.find(txAttribute[i]) == 0) { if(result != 0 && (i == int(Supports) || i == int(Never))) { _unit->warning(InvalidMetaData, "invalid freeze metadata for operation"); } else { result |= (i << 1); } freezeMD = freezeMD.substr(txAttribute[i].size()); break; // while } i++; } if(i == 4) { _unit->warning(InvalidMetaData, "invalid freeze metadata for operation"); // // Set default // if(result != 0) { result |= (int(Required) << 1); } } } return result; } else { return 0; } } FormatType Slice::Operation::format() const { FormatType format = parseFormatMetaData(getMetaData()); if(format == DefaultFormat) { ContainedPtr cont = ContainedPtr::dynamicCast(container()); assert(cont); format = parseFormatMetaData(cont->getMetaData()); } return format; } string Slice::Operation::kindOf() const { return "operation"; } void Slice::Operation::visit(ParserVisitor* visitor, bool) { visitor->visitOperation(this); } Slice::Operation::Operation(const ContainerPtr& container, const string& name, const TypePtr& returnType, bool returnIsOptional, int returnTag, Mode mode) : SyntaxTreeBase(container->unit()), Contained(container, name), Container(container->unit()), _returnType(returnType), _returnIsOptional(returnIsOptional), _returnTag(returnTag), _mode(mode) { if(returnType) { checkDeprecatedType(_unit, returnType); } } // ---------------------------------------------------------------------- // ParamDecl // ---------------------------------------------------------------------- TypePtr Slice::ParamDecl::type() const { return _type; } bool Slice::ParamDecl::isOutParam() const { return _isOutParam; } bool Slice::ParamDecl::optional() const { return _optional; } int Slice::ParamDecl::tag() const { return _tag; } Contained::ContainedType Slice::ParamDecl::containedType() const { return ContainedTypeDataMember; } bool Slice::ParamDecl::uses(const ContainedPtr& contained) const { ContainedPtr contained2 = ContainedPtr::dynamicCast(_type); if(contained2 && contained2 == contained) { return true; } return false; } string Slice::ParamDecl::kindOf() const { return "parameter declaration"; } void Slice::ParamDecl::visit(ParserVisitor* visitor, bool) { visitor->visitParamDecl(this); } Slice::ParamDecl::ParamDecl(const ContainerPtr& container, const string& name, const TypePtr& type, bool isOutParam, bool optional, int tag) : SyntaxTreeBase(container->unit()), Contained(container, name), _type(type), _isOutParam(isOutParam), _optional(optional), _tag(tag) { } // ---------------------------------------------------------------------- // DataMember // ---------------------------------------------------------------------- TypePtr Slice::DataMember::type() const { return _type; } bool Slice::DataMember::optional() const { return _optional; } int Slice::DataMember::tag() const { return _tag; } string Slice::DataMember::defaultValue() const { return _defaultValue; } string Slice::DataMember::defaultLiteral() const { return _defaultLiteral; } SyntaxTreeBasePtr Slice::DataMember::defaultValueType() const { return _defaultValueType; } Contained::ContainedType Slice::DataMember::containedType() const { return ContainedTypeDataMember; } bool Slice::DataMember::uses(const ContainedPtr& contained) const { ContainedPtr contained2 = ContainedPtr::dynamicCast(_type); if(contained2 && contained2 == contained) { return true; } return false; } string Slice::DataMember::kindOf() const { return "data member"; } void Slice::DataMember::visit(ParserVisitor* visitor, bool) { visitor->visitDataMember(this); } Slice::DataMember::DataMember(const ContainerPtr& container, const string& name, const TypePtr& type, bool optional, int tag, const SyntaxTreeBasePtr& defaultValueType, const string& defaultValue, const string& defaultLiteral) : SyntaxTreeBase(container->unit()), Contained(container, name), _type(type), _optional(optional), _tag(tag), _defaultValueType(defaultValueType), _defaultValue(defaultValue), _defaultLiteral(defaultLiteral) { } // ---------------------------------------------------------------------- // Unit // ---------------------------------------------------------------------- UnitPtr Slice::Unit::createUnit(bool ignRedefs, bool all, bool allowIcePrefix, bool allowUnderscore, const StringList& defaultGlobalMetadata) { return new Unit(ignRedefs, all, allowIcePrefix, allowUnderscore, defaultGlobalMetadata); } bool Slice::Unit::ignRedefs() const { return _ignRedefs; } bool Slice::Unit::allowIcePrefix() const { return _allowIcePrefix; } bool Slice::Unit::allowUnderscore() const { return _allowUnderscore; } void Slice::Unit::setComment(const string& comment) { _currentComment = ""; string::size_type end = 0; while(true) { string::size_type begin; if(end == 0) { // // Skip past the initial whitespace. // begin = comment.find_first_not_of(" \t\r\n*", end); } else { // // Skip more whitespace but retain blank lines. // begin = comment.find_first_not_of(" \t*", end); } if(begin == string::npos) { break; } end = comment.find('\n', begin); if(end != string::npos) { if(end + 1 > begin) { _currentComment += comment.substr(begin, end + 1 - begin); } ++end; } else { end = comment.find_last_not_of(" \t\r\n*"); if(end != string::npos) { if(end + 1 > begin) { _currentComment += comment.substr(begin, end + 1 - begin); } } break; } } } string Slice::Unit::currentComment() { string comment = ""; comment.swap(_currentComment); return comment; } string Slice::Unit::currentFile() const { DefinitionContextPtr dc = currentDefinitionContext(); if(dc) { return dc->filename(); } else { return string(); } } string Slice::Unit::topLevelFile() const { return _topLevelFile; } int Slice::Unit::currentLine() const { return _currentLine; } void Slice::Unit::nextLine() { _currentLine++; } bool Slice::Unit::scanPosition(const char* s) { assert(*s == '#'); string line(s + 1); // Skip leading # eraseWhiteSpace(line); if(line.find("line", 0) == 0) // Erase optional "line" { line.erase(0, 4); eraseWhiteSpace(line); } string::size_type idx; _currentLine = atoi(line.c_str()) - 1; // Read line number idx = line.find_first_of(" \t\r"); // Erase line number if(idx != string::npos) { line.erase(0, idx); } eraseWhiteSpace(line); string currentFile; if(!line.empty()) { if(line[0] == '"') { idx = line.rfind('"'); if(idx != string::npos) { currentFile = line.substr(1, idx - 1); } } else { currentFile = line; } } enum LineType { File, Push, Pop }; LineType type = File; if(_currentLine == 0) { if(_currentIncludeLevel > 0 || currentFile != _topLevelFile) { type = Push; line.erase(idx); eraseWhiteSpace(line); } } else { DefinitionContextPtr dc = currentDefinitionContext(); if(dc != 0 && !dc->filename().empty() && dc->filename() != currentFile) { type = Pop; line.erase(idx); eraseWhiteSpace(line); } } switch(type) { case Push: { if(++_currentIncludeLevel == 1) { if(find(_includeFiles.begin(), _includeFiles.end(), currentFile) == _includeFiles.end()) { _includeFiles.push_back(currentFile); } } pushDefinitionContext(); _currentComment = ""; break; } case Pop: { --_currentIncludeLevel; popDefinitionContext(); _currentComment = ""; break; } default: { break; // Do nothing } } if(!currentFile.empty()) { DefinitionContextPtr dc = currentDefinitionContext(); assert(dc); dc->setFilename(currentFile); _definitionContextMap.insert(make_pair(currentFile, dc)); } // // Return code indicates whether starting parse of a new file. // return _currentLine == 0; } int Slice::Unit::currentIncludeLevel() const { if(_all) { return 0; } else { return _currentIncludeLevel; } } void Slice::Unit::addGlobalMetaData(const StringList& metaData) { DefinitionContextPtr dc = currentDefinitionContext(); assert(dc); if(dc->seenDefinition()) { error("file metadata must appear before any definitions"); } else { // // Append the file metadata to any existing metadata (e.g., default file metadata). // StringList l = dc->getMetaData(); copy(metaData.begin(), metaData.end(), back_inserter(l)); dc->setMetaData(l); } } void Slice::Unit::setSeenDefinition() { DefinitionContextPtr dc = currentDefinitionContext(); assert(dc); dc->setSeenDefinition(); } void Slice::Unit::error(const string& s) { emitError(currentFile(), _currentLine, s); _errors++; } void Slice::Unit::warning(WarningCategory category, const string& msg) const { if(_definitionContextStack.empty()) { emitWarning(currentFile(), _currentLine, msg); } else { _definitionContextStack.top()->warning(category, currentFile(), _currentLine, msg); } } ContainerPtr Slice::Unit::currentContainer() const { assert(!_containerStack.empty()); return _containerStack.top(); } void Slice::Unit::pushContainer(const ContainerPtr& cont) { _containerStack.push(cont); } void Slice::Unit::popContainer() { assert(!_containerStack.empty()); _containerStack.pop(); } DefinitionContextPtr Slice::Unit::currentDefinitionContext() const { DefinitionContextPtr dc; if(!_definitionContextStack.empty()) { dc = _definitionContextStack.top(); } return dc; } void Slice::Unit::pushDefinitionContext() { _definitionContextStack.push(new DefinitionContext(_currentIncludeLevel, _defaultGlobalMetaData)); } void Slice::Unit::popDefinitionContext() { assert(!_definitionContextStack.empty()); _definitionContextStack.pop(); } DefinitionContextPtr Slice::Unit::findDefinitionContext(const string& file) const { map::const_iterator p = _definitionContextMap.find(file); if(p != _definitionContextMap.end()) { return p->second; } return 0; } void Slice::Unit::addContent(const ContainedPtr& contained) { string scoped = IceUtilInternal::toLower(contained->scoped()); _contentMap[scoped].push_back(contained); } void Slice::Unit::removeContent(const ContainedPtr& contained) { string scoped = IceUtilInternal::toLower(contained->scoped()); map::iterator p = _contentMap.find(scoped); assert(p != _contentMap.end()); for(ContainedList::iterator q = p->second.begin(); q != p->second.end(); ++q) { if(q->get() == contained.get()) { p->second.erase(q); return; } } assert(false); } ContainedList Slice::Unit::findContents(const string& scoped) const { assert(!scoped.empty()); assert(scoped[0] == ':'); string name = IceUtilInternal::toLower(scoped); map::const_iterator p = _contentMap.find(name); if(p != _contentMap.end()) { return p->second; } else { return ContainedList(); } } ClassList Slice::Unit::findDerivedClasses(const ClassDefPtr& cl) const { ClassList derived; for(map::const_iterator p = _contentMap.begin(); p != _contentMap.end(); ++p) { for(ContainedList::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { ClassDefPtr r = ClassDefPtr::dynamicCast(*q); if(r) { ClassList bases = r->bases(); if(find(bases.begin(), bases.end(), cl) != bases.end()) { derived.push_back(r); } } } } derived.sort(); derived.unique(); return derived; } ExceptionList Slice::Unit::findDerivedExceptions(const ExceptionPtr& ex) const { ExceptionList derived; for(map::const_iterator p = _contentMap.begin(); p != _contentMap.end(); ++p) { for(ContainedList::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { ExceptionPtr r = ExceptionPtr::dynamicCast(*q); if(r) { ExceptionPtr base = r->base(); if(base && base == ex) { derived.push_back(r); } } } } derived.sort(); derived.unique(); return derived; } ContainedList Slice::Unit::findUsedBy(const ContainedPtr& contained) const { ContainedList usedBy; for(map::const_iterator p = _contentMap.begin(); p != _contentMap.end(); ++p) { for(ContainedList::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { if((*q)->uses(contained)) { usedBy.push_back(*q); } } } usedBy.sort(); usedBy.unique(); return usedBy; } void Slice::Unit::addTypeId(int compactId, const std::string& typeId) { _typeIds.insert(make_pair(compactId, typeId)); } std::string Slice::Unit::getTypeId(int compactId) const { map::const_iterator p = _typeIds.find(compactId); if(p != _typeIds.end()) { return p->second; } return string(); } bool Slice::Unit::hasCompactTypeId() const { return _typeIds.size() > 0; } bool Slice::Unit::usesNonLocals() const { for(map::const_iterator p = _contentMap.begin(); p != _contentMap.end(); ++p) { for(ContainedList::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { ConstructedPtr constr = ConstructedPtr::dynamicCast(*q); if(constr && !constr->isLocal()) { return true; } ExceptionPtr exc = ExceptionPtr::dynamicCast(*q); if(exc && !exc->isLocal()) { return true; } } } if(_builtins.find(Builtin::KindObject) != _builtins.end()) { return true; } if(_builtins.find(Builtin::KindObjectProxy) != _builtins.end()) { return true; } if(_builtins.find(Builtin::KindValue) != _builtins.end()) { return true; } return false; } bool Slice::Unit::usesConsts() const { for(map::const_iterator p = _contentMap.begin(); p != _contentMap.end(); ++p) { for(ContainedList::const_iterator q = p->second.begin(); q != p->second.end(); ++q) { ConstPtr cd = ConstPtr::dynamicCast(*q); if(cd) { return true; } } } return false; } StringList Slice::Unit::includeFiles() const { return _includeFiles; } StringList Slice::Unit::allFiles() const { StringList result; for(map::const_iterator p = _definitionContextMap.begin(); p != _definitionContextMap.end(); ++p) { result.push_back(p->first); } return result; } int Slice::Unit::parse(const string& filename, FILE* file, bool debug) { slice_debug = debug ? 1 : 0; assert(!Slice::unit); Slice::unit = this; _currentComment = ""; _currentLine = 1; _currentIncludeLevel = 0; _topLevelFile = fullPath(filename); pushContainer(this); pushDefinitionContext(); // // MCPP Fix: mcpp doesn't always output the first #line when mcpp_lib_main is // called repeatedly. We scan a fake #line here to ensure the top definition // context is correctly initialized. // scanPosition(string("#line 1 " + _topLevelFile).c_str()); slice_in = file; int status = slice_parse(); if(_errors) { status = EXIT_FAILURE; } if(status == EXIT_FAILURE) { while(!_containerStack.empty()) { popContainer(); } while(!_definitionContextStack.empty()) { popDefinitionContext(); } } else { assert(_containerStack.size() == 1); popContainer(); assert(_definitionContextStack.size() == 1); popDefinitionContext(); } Slice::unit = 0; return status; } void Slice::Unit::destroy() { _contentMap.clear(); _builtins.clear(); Container::destroy(); } void Slice::Unit::visit(ParserVisitor* visitor, bool all) { if(visitor->visitUnitStart(this)) { Container::visit(visitor, all); visitor->visitUnitEnd(this); } } BuiltinPtr Slice::Unit::builtin(Builtin::Kind kind) { map::const_iterator p = _builtins.find(kind); if(p != _builtins.end()) { return p->second; } BuiltinPtr builtin = new Builtin(this, kind); _builtins.insert(make_pair(kind, builtin)); return builtin; } void Slice::Unit::addTopLevelModule(const string& file, const string& module) { map >::iterator i = _fileTopLevelModules.find(file); if(i == _fileTopLevelModules.end()) { set modules; modules.insert(module); _fileTopLevelModules.insert(make_pair(file, modules)); } else { i->second.insert(module); } } set Slice::Unit::getTopLevelModules(const string& file) const { map >::const_iterator i = _fileTopLevelModules.find(file); if(i == _fileTopLevelModules.end()) { return set(); } else { return i->second; } } Slice::Unit::Unit(bool ignRedefs, bool all, bool allowIcePrefix, bool allowUnderscore, const StringList& defaultGlobalMetadata) : SyntaxTreeBase(0), Container(0), _ignRedefs(ignRedefs), _all(all), _allowIcePrefix(allowIcePrefix), _allowUnderscore(allowUnderscore), _defaultGlobalMetaData(defaultGlobalMetadata), _errors(0), _currentLine(0), _currentIncludeLevel(0) { _unit = this; } void Slice::Unit::eraseWhiteSpace(string& s) { string::size_type idx = s.find_first_not_of(" \t\r"); if(idx != string::npos) { s.erase(0, idx); } idx = s.find_last_not_of(" \t\r"); if(idx != string::npos) { s.erase(++idx); } } // ---------------------------------------------------------------------- // CICompare // ---------------------------------------------------------------------- bool Slice::CICompare::operator()(const string& s1, const string& s2) const { string::const_iterator p1 = s1.begin(); string::const_iterator p2 = s2.begin(); while(p1 != s1.end() && p2 != s2.end() && ::tolower(static_cast(*p1)) == ::tolower(static_cast(*p2))) { ++p1; ++p2; } if(p1 == s1.end() && p2 == s2.end()) { return false; } else if(p1 == s1.end()) { return true; } else if(p2 == s2.end()) { return false; } else { return ::tolower(static_cast(*p1)) < ::tolower(static_cast(*p2)); } } #if defined(__SUNPRO_CC) bool Slice::cICompare(const std::string& s1, const std::string& s2) { CICompare c; return c(s1, s2); } #endif // ---------------------------------------------------------------------- // DerivedToBaseCompare // ---------------------------------------------------------------------- bool Slice::DerivedToBaseCompare::operator()(const ExceptionPtr& e1, const ExceptionPtr& e2) const { return e2->isBaseOf(e1); } #if defined(__SUNPRO_CC) bool Slice::derivedToBaseCompare(const ExceptionPtr& e1, const ExceptionPtr& e2) { return e2->isBaseOf(e1); } #endif