summaryrefslogtreecommitdiff
path: root/cpp/src/Slice/Parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Slice/Parser.cpp')
-rw-r--r--cpp/src/Slice/Parser.cpp5886
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