diff options
Diffstat (limited to 'cpp/src/Slice/Parser.cpp')
-rw-r--r-- | cpp/src/Slice/Parser.cpp | 5886 |
1 files changed, 5886 insertions, 0 deletions
diff --git a/cpp/src/Slice/Parser.cpp b/cpp/src/Slice/Parser.cpp new file mode 100644 index 00000000000..075128f0a85 --- /dev/null +++ b/cpp/src/Slice/Parser.cpp @@ -0,0 +1,5886 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/Functional.h> +#include <IceUtil/InputUtil.h> +#include <IceUtil/StringUtil.h> +#include <IceUtil/Unicode.h> +#include <Slice/Parser.h> +#include <Slice/GrammarUtil.h> +#include <Slice/Util.h> +#include <cstring> +#include <iterator> + +#ifdef _WIN32 +# include <io.h> +#endif + +using namespace std; +using namespace Slice; + +extern FILE* slice_in; +extern int slice_debug; + +// +// 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 }; + +} + + + +namespace Slice +{ + +Unit* unit; + +} + +// ---------------------------------------------------------------------- +// DefinitionContext +// ---------------------------------------------------------------------- + +Slice::DefinitionContext::DefinitionContext(int includeLevel, const StringList& metaData) : + _includeLevel(includeLevel), _metaData(metaData), _seenDefinition(false) +{ +} + +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; +} + +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; +} + +// ---------------------------------------------------------------------- +// 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& unit) : + _unit(unit) +{ + if(_unit) + { + _definitionContext = unit->currentDefinitionContext(); + } +} + +// ---------------------------------------------------------------------- +// Type +// ---------------------------------------------------------------------- + +Slice::Type::Type(const UnitPtr& unit) : + SyntaxTreeBase(unit) +{ +} + +// ---------------------------------------------------------------------- +// 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; + } + } + assert(false); + return ""; // Keep the compiler happy. +} + +bool +Slice::Builtin::usesClasses() const +{ + return _kind == KindObject; +} + +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. + 4, // KindObject: at least 4 bytes (to marshal an index instead of an instance). + 2 // KindObjectProxy: at least an empty identity for a nil proxy, that is, 2 bytes. + }; + + assert(_kind != KindLocalObject); + return minWireSizeTable[_kind]; +} + +bool +Slice::Builtin::isVariableLength() const +{ + return _kind == KindString || _kind == KindObject || _kind == KindObjectProxy; +} + +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" + }; + +Slice::Builtin::Builtin(const UnitPtr& unit, Kind kind) : + SyntaxTreeBase(unit), + Type(unit), + _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 flattenedScope; + for(string::const_iterator r = s.begin(); r != s.end(); ++r) + { + flattenedScope += ((*r) == ':') ? '_' : *r; + } + return flattenedScope; +} + +string +Slice::Contained::file() const +{ + return _file; +} + +string +Slice::Contained::line() const +{ + return _line; +} + +string +Slice::Contained::comment() const +{ + 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<string>::const_iterator p = _metaData.begin(); p != _metaData.end(); ++p) + { + if(p->find(prefix) == 0) + { + meta = *p; + return true; + } + } + + return false; +} + +list<string> +Slice::Contained::getMetaData() const +{ + return _metaData; +} + +void +Slice::Contained::setMetaData(const list<string>& 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); +} + +bool +Slice::Contained::operator<(const Contained& rhs) const +{ + return _scoped < rhs._scoped; +} + +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) +{ + checkIdentifier(name); + ContainedList matches = _unit->findContents(thisScope() + name); + matches.sort(); // Modules can occur many times... + matches.unique(); // ... but we only want one instance of each. + + 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, bool intf, const ClassList& bases, bool local) +{ + checkIdentifier(name); + 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, 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) +{ + checkIdentifier(name); + + 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) +{ + checkIdentifier(name); + + 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); + } + } + + 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) +{ + checkIdentifier(name); + + 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); + } + } + + 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) +{ + checkIdentifier(name); + + if(_unit->profile() == IceE && !local) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(type)) + { + string msg = "Sequence `" + name + "' cannot contain object values."; + _unit->error(msg); + return 0; + } + } + + 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); + } + } + + 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); + } + + 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) +{ + checkIdentifier(name); + + if(_unit->profile() == IceE && !local) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(valueType); + if((builtin && builtin->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(valueType)) + { + string msg = "Dictionary `" + name + "' cannot contain object values."; + _unit->error(msg); + return 0; + } + } + + 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); + } + } + + 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("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); + } + } + + 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) +{ + checkIdentifier(name); + + 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); + } + } + + 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) +{ + checkIdentifier(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) + { + string msg = "redefinition of " + matches.front()->kindOf() + " `" + matches.front()->name(); + msg += "' as enumerator"; + _unit->error(msg); + } + else + { + string msg = "enumerator `" + name + "' differs only in capitalization from "; + msg += matches.front()->kindOf() + " `" + matches.front()->name() + "'"; + _unit->error(msg); + } + } + + nameIsLegal(name, "enumerator"); // Don't return here -- we create the enumerator anyway. + + EnumeratorPtr p = new Enumerator(this, name); + _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) +{ + checkIdentifier(name); + + 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); + } + } + + 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. + } + + // + // Validate the constant and its value. + // + if(nt == Real && !validateConstant(name, constType, valueType, value, true)) + { + return 0; + } + + ConstPtr p = new Const(this, name, constType, metaData, valueType, 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<Builtin::Kind>(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) +{ + // + // 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; + 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() + "'"; + _unit->error(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) + { + if(printError) + { + string msg = "`"; + msg += sc; + msg += "' is not a type"; + _unit->error(msg); + } + return TypeList(); + } + results.push_back(type); + } + } + + if(results.empty()) + { + ContainedPtr contained = ContainedPtr::dynamicCast(this); + if(!contained) + { + if(printError) + { + string msg = "`"; + msg += sc; + msg += "' is not defined"; + _unit->error(msg); + } + return TypeList(); + } + return contained->container()->lookupTypeNoBuiltin(sc, printError); + } + else + { + 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; +} + +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::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::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::hasAbstractClassDefs() const +{ + for(ContainedList::const_iterator p = _contents.begin(); p != _contents.end(); ++p) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(*p); + if(cl && cl->isAbstract()) + { + return true; + } + + ContainerPtr container = ContainerPtr::dynamicCast(*p); + if(container && container->hasAbstractClassDefs()) + { + 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("ami") || cl->hasMetaData("amd"))) + { + return true; + } + for(OperationList::const_iterator i = ops.begin(); i != ops.end(); ++i) + { + OperationPtr op = *i; + if(op->hasMetaData("ami") || 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<Container*>(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 global 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("global 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<ConstructedPtr>& dependencies) +{ + ContainedList::iterator p; + for(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(namedThing == 0) + { + 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<string, ContainedPtr, CICompare>::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) + { + _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<Unit*>(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) +{ +} + +void +Slice::Container::checkIdentifier(const string& name) const +{ + // + // Weed out identifiers with reserved suffixes. + // + static const string suffixBlacklist[] = { "Helper", "Holder", "Prx", "Ptr" }; + for(size_t i = 0; i < sizeof(suffixBlacklist) / sizeof(*suffixBlacklist); ++i) + { + if(name.find(suffixBlacklist[i], name.size() - suffixBlacklist[i].size()) != string::npos) + { + _unit->error("illegal identifier `" + name + "': `" + suffixBlacklist[i] + "' suffix is reserved"); + } + } + + // + // Check for illegal underscores. + // + if(name.find('_') == 0) + { + _unit->error("illegal leading underscore in identifier `" + name + "'"); + } + else if(name.rfind('_') == name.size() - 1) + { + _unit->error("illegal trailing underscore in identifier `" + name + "'"); + } + else if(name.find("__") != string::npos) + { + _unit->error("illegal double underscore in identifier `" + name + "'"); + } + else if(_unit->currentIncludeLevel() == 0 && !_unit->allowUnderscore() && name.find('_') != string::npos) + { + // + // For rules controlled by a translator option, we don't complain about included files. + // + _unit->error("illegal underscore in identifier `" + name + "'"); + } + + if(_unit->currentIncludeLevel() == 0 && !_unit->allowIcePrefix()) + { + // + // For rules controlled by a translator option, we don't complain about included files. + // + if(name.size() >= 3) + { + string prefix3; + prefix3 += ::tolower(static_cast<unsigned char>(name[0])); + prefix3 += ::tolower(static_cast<unsigned char>(name[1])); + prefix3 += ::tolower(static_cast<unsigned char>(name[2])); + if(prefix3 == "ice") + { + _unit->error("illegal identifier `" + name + "': `" + name.substr(0, 3) + "' prefix is reserved"); + } + } + } +} + +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 global 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, const 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) + { +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530) + // Strange Sun C++ 5.3 bug. + const IceUtil::HandleBase<SyntaxTreeBase>& hb = constant->type(); + lt = BuiltinPtr::dynamicCast(hb); +#else + lt = BuiltinPtr::dynamicCast(constant->type()); +#endif + } + else + { +#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530) + // Strange Sun C++ 5.3 bug. + const IceUtil::HandleBase<SyntaxTreeBase>& hb = valueType; + lt = BuiltinPtr::dynamicCast(hb); +#else + lt = BuiltinPtr::dynamicCast(valueType); +#endif + } + + 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: + { + 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 + { + 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->getEnumerators(); + 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; + } + } + } + + return true; +} + +// ---------------------------------------------------------------------- +// 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<ConstructedPtr> 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<ConstructedPtr>::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 4; // 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<ConstructedPtr>& dependencies) +{ + if(_definition) + { + _definition->containerRecDependencies(dependencies); + ClassList bases = _definition->bases(); + ClassList::iterator p; + for(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& unit) +{ + // + // 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() << "'"; + unit->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, unit); + } +} + +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& unit) +{ + set<string> 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"; + unit->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"; + unit->error(msg); + reported.insert(*s1); + reported.insert(*s2); + } + } + } + } + } +} + +// ---------------------------------------------------------------------- +// ClassDef +// ---------------------------------------------------------------------- + +void +Slice::ClassDef::destroy() +{ + _declaration = 0; + _bases.empty(); + Container::destroy(); +} + +OperationPtr +Slice::ClassDef::createOperation(const string& name, + const TypePtr& returnType, + Operation::Mode mode) +{ + checkIdentifier(name); + + 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 newName = IceUtilInternal::toLower(name); + if(baseName == newName) + { + 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); + } + + _hasOperations = true; + OperationPtr op = new Operation(this, name, returnType, mode); + _contents.push_back(op); + return op; +} + +DataMemberPtr +Slice::ClassDef::createDataMember(const string& name, const TypePtr& type, const SyntaxTreeBasePtr& defaultValueType, + const string& defaultValue, const string& defaultLiteral) +{ + checkIdentifier(name); + + if(_unit->profile() == IceE) + { + if(!isLocal()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if((builtin && builtin->kind() == Builtin::KindObject)) + { + string msg = "Class data member `" + name + "' cannot be a value object."; + _unit->error(msg); + return 0; + } + + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type); + if(classDecl != 0 && !classDecl->isLocal()) + { + string msg = "Class data member `" + name + "' cannot be a value object."; + _unit->error(msg); + return 0; + } + } + } + + 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; + } + } + + // + // Check whether enclosing class has the same name. + // + if(name == this->name()) + { + string msg = "class name `"; + msg += name; + msg += "' cannot be used as data member name"; + _unit->error(msg); + return 0; + } + + string newName = IceUtilInternal::toLower(name); + string thisName = IceUtilInternal::toLower(this->name()); + if(newName == thisName) + { + string msg = "data member `" + name + "' differs only in capitalization from enclosing class name `"; + msg += 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 = "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 newName = IceUtilInternal::toLower(name); + if(baseName == newName) + { + 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) + { + // + // 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(); + } + } + + _hasDataMembers = true; + DataMemberPtr member = new DataMember(this, name, type, 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 = operations(); + result.sort(); + result.unique(); + for(ClassList::const_iterator p = _bases.begin(); p != _bases.end(); ++p) + { + OperationList li = (*p)->allOperations(); + result.merge(li); + result.unique(); + } + 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; +} + +// +// 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) || 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; +} + +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); + } +} + +Slice::ClassDef::ClassDef(const ContainerPtr& container, const string& name, 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) +{ + // + // 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 +} + +// ---------------------------------------------------------------------- +// Proxy +// ---------------------------------------------------------------------- + +bool +Slice::Proxy::isLocal() const +{ + return __class->isLocal(); +} + +string +Slice::Proxy::typeId() const +{ + return __class->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 __class; +} + +Slice::Proxy::Proxy(const ClassDeclPtr& cl) : + SyntaxTreeBase(cl->unit()), + Type(cl->unit()), + __class(cl) +{ +} + +// ---------------------------------------------------------------------- +// Exception +// ---------------------------------------------------------------------- + +void +Slice::Exception::destroy() +{ + _base = 0; + Container::destroy(); +} + +DataMemberPtr +Slice::Exception::createDataMember(const string& name, const TypePtr& type, const SyntaxTreeBasePtr& defaultValueType, + const string& defaultValue, const string& defaultLiteral) +{ + checkIdentifier(name); + + if(_unit->profile() == IceE) + { + if(!isLocal()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if((builtin && builtin->kind() == Builtin::KindObject)) + { + string msg = "Exception data member `" + name + "' cannot be a value object."; + _unit->error(msg); + return 0; + } + + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type); + if(classDecl != 0 && !classDecl->isLocal()) + { + string msg = "Exception data member `" + name + "' cannot be a value object."; + _unit->error(msg); + return 0; + } + } + } + + 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; + } + } + + // + // Check whether enclosing exception has the same name. + // + if(name == this->name()) + { + string msg = "exception name `"; + msg += name; + msg += "' cannot be used as exception member name"; + _unit->error(msg); + return 0; + } + + string newName = IceUtilInternal::toLower(name); + string thisName = IceUtilInternal::toLower(this->name()); + if(newName == thisName) + { + string msg = "exception member `" + name + "' differs only in capitalization "; + msg += "from enclosing exception name `" + this->name() + "'"; + _unit->error(msg); + } + + // + // 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 newName = IceUtilInternal::toLower(name); + if(baseName == newName) + { + 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) + { + // + // 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(); + } + } + + DataMemberPtr p = new DataMember(this, name, type, 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; +} + +// +// 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) || 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() const +{ + DataMemberList dml = dataMembers(); + for(DataMemberList::const_iterator i = dml.begin(); i != dml.end(); ++i) + { + if((*i)->type()->usesClasses()) + { + return true; + } + } + if(_base) + { + return _base->usesClasses(); + } + 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; +} + +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, const SyntaxTreeBasePtr& defaultValueType, + const string& defaultValue, const string& defaultLiteral) +{ + checkIdentifier(name); + + if(_unit->profile() == IceE) + { + if(!isLocal()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if((builtin && builtin->kind() == Builtin::KindObject)) + { + string msg = "Struct data member `" + name + "' cannot be a value object."; + _unit->error(msg); + return 0; + } + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type); + if(classDecl != 0 && !classDecl->isLocal()) + { + string msg = "Struct data member `" + name + "' cannot be a value object."; + _unit->error(msg); + return 0; + } + } + } + + 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; + } + } + + // + // Check whether enclosing struct has the same name. + // + if(name == this->name()) + { + string msg = "struct name `"; + msg += name; + msg += "' cannot be used as member name"; + _unit->error(msg); + return 0; + } + + string newName = IceUtilInternal::toLower(name); + string thisName = IceUtilInternal::toLower(this->name()); + if(newName == thisName) + { + string msg = "struct member `" + name + "' differs only in capitalization from enclosing struct name `"; + msg += this->name() + "'"; + _unit->error(msg); + } + + // + // 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) + { + // + // 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(); + } + } + + DataMemberPtr p = new DataMember(this, name, type, 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) || 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<ConstructedPtr>& 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<ConstructedPtr>& 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<ConstructedPtr>& 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: + { + 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() +{ + _enumerators.clear(); + SyntaxTreeBase::destroy(); +} + +EnumeratorList +Slice::Enum::getEnumerators() +{ + return _enumerators; +} + +void +Slice::Enum::setEnumerators(const EnumeratorList& ens) +{ + _enumerators = ens; + for(EnumeratorList::iterator p = _enumerators.begin(); p != _enumerators.end(); ++p) + { + (*p)->_type = this; + } +} + +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 +{ + size_t sz = _enumerators.size(); + if(sz <= 0x7f) + { + return 1; + } + if(sz <= 0x7fff) + { + return 2; + } + return 4; +} + +bool +Slice::Enum::isVariableLength() const +{ + return false; +} + +string +Slice::Enum::kindOf() const +{ + return "enumeration"; +} + +void +Slice::Enum::visit(ParserVisitor* visitor, bool) +{ + visitor->visitEnum(this); +} + +void +Slice::Enum::recDependencies(set<ConstructedPtr>&) +{ + // An Enum does not have any dependencies. +} + +Slice::Enum::Enum(const ContainerPtr& container, const string& name, bool local) : + SyntaxTreeBase(container->unit()), + Type(container->unit()), + Contained(container, name), + Constructed(container, name, local) +{ +} + +// ---------------------------------------------------------------------- +// Enumerator +// ---------------------------------------------------------------------- + +EnumPtr +Slice::Enumerator::type() const +{ + return _type; +} + +Contained::ContainedType +Slice::Enumerator::containedType() const +{ + return ContainedTypeEnumerator; +} + +bool +Slice::Enumerator::uses(const ContainedPtr&) const +{ + return false; +} + +string +Slice::Enumerator::kindOf() const +{ + return "enumerator"; +} + +Slice::Enumerator::Enumerator(const ContainerPtr& container, const string& name) : + SyntaxTreeBase(container->unit()), + Contained(container, name) +{ +} + +// ---------------------------------------------------------------------- +// 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) +{ +} + +// ---------------------------------------------------------------------- +// Operation +// ---------------------------------------------------------------------- + +TypePtr +Slice::Operation::returnType() const +{ + return _returnType; +} + +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; + } +} + +ParamDeclPtr +Slice::Operation::createParamDecl(const string& name, const TypePtr& type, bool isOutParam) +{ + checkIdentifier(name); + + if(_unit->profile() == IceE) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container()); + assert(cl); + if(!cl->isLocal()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(type); + if((builtin && builtin->kind() == Builtin::KindObject)) + { + string msg = "Object `" + name + "' cannot be passed by value."; + _unit->error(msg); + return 0; + } + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type); + if(classDecl != 0 && !classDecl->isLocal()) + { + string msg = "Object `" + name + "' cannot be passed by value."; + _unit->error(msg); + return 0; + } + } + } + + 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; + } + } + + // + // Check whether enclosing operation has the same name. + // + if(name == this->name()) + { + string msg = "operation name `"; + msg += name; + msg += "' cannot be used as parameter name"; + _unit->error(msg); + return 0; + } + + string newName = IceUtilInternal::toLower(name); + string thisName = IceUtilInternal::toLower(this->name()); + if(newName == thisName) + { + string msg = "parameter `" + name + "' differs only in capitalization from operation name `"; + msg += this->name() + "'"; + _unit->error(msg); + } + + // + // 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); + } + + ParamDeclPtr p = new ParamDecl(this, name, type, isOutParam); + _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; +} + +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; + } + } + + ExceptionList::const_iterator q; + + for(q = _throws.begin(); q != _throws.end(); ++q) + { + ContainedPtr contained2 = ContainedPtr::dynamicCast(*q); + if(contained2 && contained2 == contained) + { + return true; + } + } + + return false; +} + +bool +Slice::Operation::sendsClasses() const +{ + ParamDeclList pdl = parameters(); + for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) + { + if(!(*i)->isOutParam() && (*i)->type()->usesClasses()) + { + return true; + } + } + return false; +} + +bool +Slice::Operation::returnsClasses() const +{ + TypePtr t = returnType(); + if(t && t->usesClasses()) + { + return true; + } + ParamDeclList pdl = parameters(); + for(ParamDeclList::const_iterator i = pdl.begin(); i != pdl.end(); ++i) + { + if((*i)->isOutParam() && (*i)->type()->usesClasses()) + { + 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; +} + +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) + { + emitWarning(definitionContext()->filename(), line(), "invalid freeze metadata for operation"); + } + else + { + if(freezeMD.size() == 0) + { + freezeMD = (result == 0) ? ":supports" : ":required"; + } + + // + // Remove ":" + // + freezeMD = freezeMD.substr(1); + + int i = 0; + while(i < 4) + { + if(freezeMD.find(txAttribute[i]) == 0) + { + if(result != 0 && (i == int(Supports) || i == int(Never))) + { + emitWarning(definitionContext()->filename(), line(), "invalid freeze metadata for operation"); + } + else + { + result |= (i << 1); + } + freezeMD = freezeMD.substr(txAttribute[i].size()); + break; // while + } + i++; + } + + if(i == 4) + { + emitWarning(definitionContext()->filename(), line(), "invalid freeze metadata for operation"); + + // + // Set default + // + if(result != 0) + { + result |= (int(Required) << 1); + } + } + } + return result; + } + else + { + return 0; + } +} + + +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, + Mode mode) : + SyntaxTreeBase(container->unit()), + Contained(container, name), + Container(container->unit()), + _returnType(returnType), + _mode(mode) +{ + if(_unit->profile() == IceE) + { + ClassDefPtr cl = ClassDefPtr::dynamicCast(this->container()); + assert(cl); + if(!cl->isLocal()) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast(returnType); + if((builtin && builtin->kind() == Builtin::KindObject)) + { + string msg = "Method `" + name + "' cannot return an object by value."; + _unit->error(msg); + } + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(returnType); + if(classDecl != 0 && !classDecl->isLocal()) + { + string msg = "Method `" + name + "' cannot return an object by value."; + _unit->error(msg); + } + } + } +} + +// ---------------------------------------------------------------------- +// ParamDecl +// ---------------------------------------------------------------------- + +TypePtr +Slice::ParamDecl::type() const +{ + return _type; +} + +bool +Slice::ParamDecl::isOutParam() const +{ + return _isOutParam; +} + +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) : + SyntaxTreeBase(container->unit()), + Contained(container, name), + _type(type), + _isOutParam(isOutParam) +{ +} + +// ---------------------------------------------------------------------- +// DataMember +// ---------------------------------------------------------------------- + +TypePtr +Slice::DataMember::type() const +{ + return _type; +} + +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, + const SyntaxTreeBasePtr& defaultValueType, const string& defaultValue, + const string& defaultLiteral) : + SyntaxTreeBase(container->unit()), + Contained(container, name), + _type(type), + _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("global metadata must appear before any definitions"); + } + else + { + // + // Append the global metadata to any existing metadata (e.g., default global 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 char* s) +{ + emitError(currentFile(), _currentLine, s); + _errors++; +} + +void +Slice::Unit::error(const string& s) +{ + emitError(currentFile(), _currentLine, s); + _errors++; +} + +void +Slice::Unit::warning(const char* s) const +{ + emitWarning(currentFile(), _currentLine, s); +} + +void +Slice::Unit::warning(const string& s) const +{ + emitWarning(currentFile(), _currentLine, s); +} + +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<string, DefinitionContextPtr>::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<string, ContainedList>::iterator p = _contentMap.find(scoped); + assert(p != _contentMap.end()); + ContainedList::iterator q; + for(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<string, ContainedList>::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<string, ContainedList>::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<string, ContainedList>::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<string, ContainedList>::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; +} + +bool +Slice::Unit::usesProxies() const +{ + for(map<string, ContainedList>::const_iterator p = _contentMap.begin(); p != _contentMap.end(); ++p) + { + for(ContainedList::const_iterator q = p->second.begin(); q != p->second.end(); ++q) + { + ClassDeclPtr decl = ClassDeclPtr::dynamicCast(*q); + if(decl && !decl->isLocal()) + { + return true; + } + } + } + + if(_builtins.find(Builtin::KindObjectProxy) != _builtins.end()) + { + return true; + } + + return false; +} + +bool +Slice::Unit::usesNonLocals() const +{ + for(map<string, ContainedList>::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; + } + + return false; +} + +bool +Slice::Unit::usesConsts() const +{ + for(map<string, ContainedList>::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; +} + +FeatureProfile +Slice::Unit::profile() const +{ + return _featureProfile; +} + +StringList +Slice::Unit::includeFiles() const +{ + return _includeFiles; +} + +StringList +Slice::Unit::allFiles() const +{ + StringList result; + for(map<string, DefinitionContextPtr>::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::FeatureProfile profile) +{ + slice_debug = debug ? 1 : 0; + + assert(!Slice::unit); + Slice::unit = this; + + _currentComment = ""; + _currentLine = 1; + _currentIncludeLevel = 0; + _featureProfile = profile; + _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<Builtin::Kind, BuiltinPtr>::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; +} + +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<unsigned char>(*p1)) == ::tolower(static_cast<unsigned char>(*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<unsigned char>(*p1)) < ::tolower(static_cast<unsigned char>(*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 |