summaryrefslogtreecommitdiff
path: root/cpp/src
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2003-10-21 22:25:48 +0000
committerMark Spruiell <mes@zeroc.com>2003-10-21 22:25:48 +0000
commit623184c101c904eb0d456d325d3ced4d4475d3ae (patch)
tree56a4d02eeb1f966ad1f17405a9c6b2fe84e804e0 /cpp/src
parentFreeze Index Windows port (diff)
downloadice-623184c101c904eb0d456d325d3ced4d4475d3ae.tar.bz2
ice-623184c101c904eb0d456d325d3ced4d4475d3ae.tar.xz
ice-623184c101c904eb0d456d325d3ced4d4475d3ae.zip
initial check-in
Diffstat (limited to 'cpp/src')
-rw-r--r--cpp/src/Transform/.depend11
-rw-r--r--cpp/src/Transform/Analyzer.cpp1146
-rw-r--r--cpp/src/Transform/Analyzer.h41
-rw-r--r--cpp/src/Transform/Data.cpp3458
-rw-r--r--cpp/src/Transform/Data.h658
-rw-r--r--cpp/src/Transform/Error.cpp192
-rw-r--r--cpp/src/Transform/Error.h75
-rw-r--r--cpp/src/Transform/Exception.cpp60
-rw-r--r--cpp/src/Transform/Grammar.y264
-rw-r--r--cpp/src/Transform/GrammarUtil.h144
-rw-r--r--cpp/src/Transform/Makefile74
-rw-r--r--cpp/src/Transform/Node.cpp464
-rw-r--r--cpp/src/Transform/Node.h166
-rw-r--r--cpp/src/Transform/Parser.cpp75
-rw-r--r--cpp/src/Transform/Parser.h33
-rw-r--r--cpp/src/Transform/Scanner.l375
-rw-r--r--cpp/src/Transform/TransformDB.cpp563
-rw-r--r--cpp/src/Transform/TransformUtil.cpp33
-rw-r--r--cpp/src/Transform/TransformUtil.h52
-rw-r--r--cpp/src/Transform/Transformer.cpp2156
20 files changed, 10040 insertions, 0 deletions
diff --git a/cpp/src/Transform/.depend b/cpp/src/Transform/.depend
new file mode 100644
index 00000000000..d7e730e4f6b
--- /dev/null
+++ b/cpp/src/Transform/.depend
@@ -0,0 +1,11 @@
+Grammar.o: Grammar.cpp ../Transform/GrammarUtil.h ../Transform/Node.h ../Transform/Data.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h ../Transform/Error.h ../Transform/Parser.h
+Scanner.o: Scanner.cpp ../../include/IceUtil/Config.h ../Transform/GrammarUtil.h ../Transform/Node.h ../Transform/Data.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h ../Transform/Error.h ../Transform/Parser.h ../Transform/Grammar.h
+Analyzer.o: Analyzer.cpp ../Transform/Analyzer.h ../../include/Slice/Parser.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Config.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h
+Transformer.o: Transformer.cpp ../../include/Transform/Transformer.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/Transform/Exception.h ../Transform/TransformUtil.h ../Transform/Data.h ../../include/IceUtil/OutputUtil.h ../Transform/Error.h ../Transform/Parser.h ../Transform/Node.h ../Transform/Analyzer.h ../../include/IceXML/Parser.h
+Data.o: Data.cpp ../Transform/Data.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h ../Transform/Error.h ../Transform/TransformUtil.h
+Error.o: Error.cpp ../Transform/Error.h ../../include/Slice/Parser.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Config.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/InputUtil.h ../../include/Transform/Exception.h ../Transform/TransformUtil.h
+Exception.o: Exception.cpp ../../include/Transform/Exception.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h
+Node.o: Node.cpp ../Transform/Node.h ../Transform/Data.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h ../Transform/Error.h
+TransformUtil.o: TransformUtil.cpp ../Transform/TransformUtil.h ../../include/Slice/Parser.h ../../include/IceUtil/Shared.h ../../include/IceUtil/Config.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/InputUtil.h
+Parser.o: Parser.cpp ../Transform/Parser.h ../Transform/Node.h ../Transform/Data.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/IceUtil/OutputUtil.h ../Transform/Error.h ../Transform/GrammarUtil.h
+TransformDB.o: TransformDB.cpp ../../include/Slice/Preprocessor.h ../../include/IceUtil/Config.h ../../include/Transform/Transformer.h ../../include/Ice/Ice.h ../../include/Ice/Initialize.h ../../include/Ice/CommunicatorF.h ../../include/Ice/LocalObjectF.h ../../include/Ice/Handle.h ../../include/IceUtil/Handle.h ../../include/IceUtil/Exception.h ../../include/Ice/Config.h ../../include/Ice/ProxyF.h ../../include/Ice/ProxyHandle.h ../../include/Ice/ObjectF.h ../../include/Ice/Exception.h ../../include/Ice/LocalObject.h ../../include/IceUtil/Shared.h ../../include/Ice/PropertiesF.h ../../include/Ice/InstanceF.h ../../include/Ice/BuiltinSequences.h ../../include/Ice/Proxy.h ../../include/IceUtil/Mutex.h ../../include/IceUtil/Lock.h ../../include/IceUtil/ThreadException.h ../../include/Ice/ProxyFactoryF.h ../../include/Ice/ConnectionF.h ../../include/Ice/EndpointF.h ../../include/Ice/ObjectAdapterF.h ../../include/Ice/ReferenceF.h ../../include/Ice/OutgoingAsyncF.h ../../include/Ice/Current.h ../../include/Ice/Identity.h ../../include/Ice/Facet.h ../../include/Ice/Object.h ../../include/Ice/IncomingAsyncF.h ../../include/Ice/Outgoing.h ../../include/IceUtil/Monitor.h ../../include/IceUtil/Cond.h ../../include/IceUtil/Time.h ../../include/Ice/BasicStream.h ../../include/Ice/ObjectFactoryF.h ../../include/Ice/Buffer.h ../../include/Ice/Incoming.h ../../include/Ice/ServantLocatorF.h ../../include/Ice/ServantManagerF.h ../../include/Ice/Direct.h ../../include/Ice/LocalException.h ../../include/Ice/Properties.h ../../include/Ice/Logger.h ../../include/Ice/LoggerUtil.h ../../include/Ice/LoggerF.h ../../include/Ice/Stats.h ../../include/Ice/Communicator.h ../../include/Ice/StatsF.h ../../include/Ice/RouterF.h ../../include/Ice/LocatorF.h ../../include/Ice/PluginF.h ../../include/Ice/ObjectFactory.h ../../include/Ice/ObjectAdapter.h ../../include/Ice/ServantLocator.h ../../include/Ice/IdentityUtil.h ../../include/Ice/OutgoingAsync.h ../../include/Ice/IncomingAsync.h ../../include/Ice/Application.h ../../include/Slice/Parser.h ../../include/IceUtil/InputUtil.h ../../include/Transform/Exception.h ../Transform/TransformUtil.h
diff --git a/cpp/src/Transform/Analyzer.cpp b/cpp/src/Transform/Analyzer.cpp
new file mode 100644
index 00000000000..b31a4bd75ed
--- /dev/null
+++ b/cpp/src/Transform/Analyzer.cpp
@@ -0,0 +1,1146 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Analyzer.h>
+#include <IceUtil/OutputUtil.h>
+#include <map>
+
+using namespace std;
+using namespace Slice;
+using namespace IceUtil;
+
+namespace Transform
+{
+
+string typeToString(const TypePtr&);
+
+//
+// TransformVisitor visits the old definitions and compares them with
+// the new definitions.
+//
+class TransformVisitor : public ParserVisitor
+{
+public:
+
+ TransformVisitor(XMLOutput&, const UnitPtr&, const TypePtr&, const TypePtr&, const TypePtr&, const TypePtr&, bool,
+ vector<string>&, vector<string>&);
+
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+ virtual void visitEnum(const EnumPtr&);
+
+private:
+
+ void compareMembers(const DataMemberList&, const DataMemberList&);
+ void compareTypes(const string&, const TypePtr&, const TypePtr&);
+ void typeChange(const string&, const TypePtr&, const TypePtr&);
+ bool checkClasses(const ClassDeclPtr&, const ClassDeclPtr&);
+
+ XMLOutput& _out;
+ UnitPtr _newUnit;
+ bool _ignoreTypeChanges;
+ vector<string>& _missingTypes;
+ vector<string>& _errors;
+};
+
+//
+// InitVisitor visits the new definitions to find any that are not present
+// in the old definitions, and generates init elements for them.
+//
+class InitVisitor : public ParserVisitor
+{
+public:
+
+ InitVisitor(XMLOutput&, const UnitPtr&);
+
+ virtual bool visitClassDefStart(const ClassDefPtr&);
+ virtual bool visitStructStart(const StructPtr&);
+ virtual void visitSequence(const SequencePtr&);
+ virtual void visitDictionary(const DictionaryPtr&);
+ virtual void visitEnum(const EnumPtr&);
+
+private:
+
+ XMLOutput& _out;
+ UnitPtr _oldUnit;
+};
+
+}
+
+string
+Transform::typeToString(const TypePtr& type)
+{
+ BuiltinPtr b = BuiltinPtr::dynamicCast(type);
+ if(b)
+ {
+ return b->kindAsString();
+ }
+ else
+ {
+ ContainedPtr cont = ContainedPtr::dynamicCast(type);
+ assert(cont);
+ return cont->scoped();
+ }
+}
+
+////////////////////////////////////
+// TransformVisitor
+////////////////////////////////////
+
+Transform::TransformVisitor::TransformVisitor(XMLOutput& out, const UnitPtr& newUnit,
+ const TypePtr& oldKey, const TypePtr& newKey,
+ const TypePtr& oldValue, const TypePtr& newValue,
+ bool ignoreTypeChanges, vector<string>& missingTypes,
+ vector<string>& errors) :
+ _out(out), _newUnit(newUnit), _ignoreTypeChanges(ignoreTypeChanges), _missingTypes(missingTypes), _errors(errors)
+{
+ out << se("database");
+
+ string oldKeyName = typeToString(oldKey);
+ string newKeyName = typeToString(newKey);
+ if(oldKeyName == newKeyName)
+ {
+ out << attr("key", oldKeyName);
+ }
+ else
+ {
+ out << attr("key", oldKeyName + "," + newKeyName);
+ }
+
+ string oldValueName = typeToString(oldValue);
+ string newValueName = typeToString(newValue);
+ if(oldValueName == newValueName)
+ {
+ out << attr("value", oldValueName);
+ }
+ else
+ {
+ out << attr("value", oldValueName + "," + newValueName);
+ }
+
+ out << se("record");
+ compareTypes("database key", oldKey, newKey);
+ compareTypes("database value", oldValue, newValue);
+ out << ee;
+
+ out << ee;
+}
+
+bool
+Transform::TransformVisitor::visitClassDefStart(const ClassDefPtr& v)
+{
+ if(v->isInterface() || v->isLocal())
+ {
+ return false;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _newUnit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ _missingTypes.push_back(scoped);
+ return false;
+ }
+
+ ClassDeclPtr decl = ClassDeclPtr::dynamicCast(l.front());
+ if(!decl || decl->isInterface())
+ {
+ if(!_ignoreTypeChanges)
+ {
+ typeChange(scoped, v->declaration(), l.front());
+ }
+ return false;
+ }
+
+ ClassDefPtr newClass = decl->definition();
+ if(!newClass)
+ {
+ _missingTypes.push_back(scoped);
+ return false;
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- class " << scoped << " -->";
+ _out << se("transform") << attr("type", scoped);
+
+ DataMemberList oldMembers = v->allDataMembers();
+ DataMemberList newMembers = newClass->allDataMembers();
+ compareMembers(oldMembers, newMembers);
+
+ _out << ee;
+
+ return false;
+}
+
+bool
+Transform::TransformVisitor::visitStructStart(const StructPtr& v)
+{
+ if(v->isLocal())
+ {
+ return false;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _newUnit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ _missingTypes.push_back(scoped);
+ return false;
+ }
+
+ StructPtr newStruct = StructPtr::dynamicCast(l.front());
+ if(!newStruct)
+ {
+ if(!_ignoreTypeChanges)
+ {
+ typeChange(scoped, v, l.front());
+ }
+ return false;
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- struct " << scoped << " -->";
+ _out << se("transform") << attr("type", scoped);
+
+ DataMemberList oldMembers = v->dataMembers();
+ DataMemberList newMembers = newStruct->dataMembers();
+ compareMembers(oldMembers, newMembers);
+
+ _out << ee;
+
+ return false;
+}
+
+void
+Transform::TransformVisitor::visitSequence(const SequencePtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _newUnit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ _missingTypes.push_back(scoped);
+ return;
+ }
+
+ SequencePtr newSeq = SequencePtr::dynamicCast(l.front());
+ if(!newSeq)
+ {
+ if(!_ignoreTypeChanges)
+ {
+ typeChange(scoped, v, l.front());
+ }
+ return;
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- sequence " << scoped << " -->";
+ _out << se("transform") << attr("type", scoped);
+
+ compareTypes(scoped + " sequence type", v->type(), newSeq->type());
+
+ _out << ee;
+}
+
+void
+Transform::TransformVisitor::visitDictionary(const DictionaryPtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _newUnit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ _missingTypes.push_back(scoped);
+ return;
+ }
+
+ DictionaryPtr newDict = DictionaryPtr::dynamicCast(l.front());
+ if(!newDict)
+ {
+ if(!_ignoreTypeChanges)
+ {
+ typeChange(scoped, v, l.front());
+ }
+ return;
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- dictionary " << scoped << " -->";
+ _out << se("transform") << attr("type", scoped);
+
+ compareTypes(scoped + " key type", v->keyType(), newDict->keyType());
+ compareTypes(scoped + " value type", v->valueType(), newDict->valueType());
+
+ _out << ee;
+}
+
+void
+Transform::TransformVisitor::visitEnum(const EnumPtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _newUnit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ _missingTypes.push_back(scoped);
+ return;
+ }
+
+ EnumPtr newEnum = EnumPtr::dynamicCast(l.front());
+ if(!newEnum)
+ {
+ if(!_ignoreTypeChanges)
+ {
+ typeChange(scoped, v, l.front());
+ }
+ return;
+ }
+
+ map<string, int> m;
+ {
+ Slice::EnumeratorList enumerators = newEnum->getEnumerators();
+ int i = 0;
+ for(Slice::EnumeratorList::iterator p = enumerators.begin(); p != enumerators.end(); ++p, ++i)
+ {
+ m.insert(map<string, int>::value_type((*p)->name(), i));
+ }
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- enum " << scoped << " -->";
+ _out << se("transform") << attr("type", scoped);
+
+ Slice::EnumeratorList enumerators = v->getEnumerators();
+ int i = 0;
+ for(Slice::EnumeratorList::iterator p = enumerators.begin(); p != enumerators.end(); ++p, ++i)
+ {
+ map<string, int>::const_iterator q = m.find((*p)->name());
+ if(q == m.end())
+ {
+ _out.nl();
+ _out << "<!-- NOTICE: enumerator `" << (*p)->name() << "' has been removed -->";
+ }
+ else if(q->second != i)
+ {
+ _out.nl();
+ _out << "<!-- NOTICE: enumerator `" << (*p)->name() << "' has changed position -->";
+ }
+ }
+
+ _out << ee;
+}
+
+void
+Transform::TransformVisitor::compareMembers(const DataMemberList& oldMembers, const DataMemberList& newMembers)
+{
+ map<string, DataMemberPtr> oldMap, newMap;
+ map<string, DataMemberPtr>::iterator q;
+ DataMemberList::const_iterator p;
+
+ for(p = oldMembers.begin(); p != oldMembers.end(); ++p)
+ {
+ oldMap.insert(pair<const string, const DataMemberPtr>((*p)->name(), *p));
+ }
+
+ for(p = newMembers.begin(); p != newMembers.end(); ++p)
+ {
+ newMap.insert(pair<const string, const DataMemberPtr>((*p)->name(), *p));
+ }
+
+ for(p = oldMembers.begin(); p != oldMembers.end(); ++p)
+ {
+ string name = (*p)->name();
+ q = newMap.find(name);
+ if(q == newMap.end())
+ {
+ _out.nl();
+ _out << "<!-- NOTICE: " << name << " has been removed -->";
+ }
+ else
+ {
+ TypePtr oldType = (*p)->type();
+ TypePtr newType = q->second->type();
+ compareTypes(name, oldType, newType);
+
+ //
+ // Remove this entry from the map to indicate that we've
+ // already seen it.
+ //
+ newMap.erase(q);
+ }
+ }
+
+ //
+ // Iterate over the remaining entries in newMap. These represent
+ // members that were added in the new definition.
+ //
+ for(q = newMap.begin(); q != newMap.end(); ++q)
+ {
+ _out.nl();
+ _out << "<!-- NOTICE: " << q->first << " has been added -->";
+ }
+}
+
+void
+Transform::TransformVisitor::compareTypes(const string& desc, const TypePtr& oldType, const TypePtr& newType)
+{
+ assert(!oldType->isLocal());
+ if(newType->isLocal())
+ {
+ ostringstream ostr;
+ ostr << desc << " has changed to a local type";
+ _errors.push_back(ostr.str());
+ return;
+ }
+
+ BuiltinPtr b = BuiltinPtr::dynamicCast(oldType);
+ if(b)
+ {
+ BuiltinPtr newb = BuiltinPtr::dynamicCast(newType);
+ switch(b->kind())
+ {
+ case Builtin::KindByte:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindBool:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case Builtin::KindBool:
+ {
+ if(newb && (newb->kind() == Builtin::KindBool || newb->kind() == Builtin::KindString))
+ {
+ return;
+ }
+
+ break;
+ }
+ case Builtin::KindShort:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindBool:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case Builtin::KindInt:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindBool:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case Builtin::KindLong:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindBool:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case Builtin::KindFloat:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindBool:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case Builtin::KindDouble:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindString:
+ {
+ return;
+ }
+ case Builtin::KindByte:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindBool:
+ case Builtin::KindObject:
+ case Builtin::KindObjectProxy:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ case Builtin::KindString:
+ {
+ if(newb)
+ {
+ switch(newb->kind())
+ {
+ case Builtin::KindByte:
+ case Builtin::KindBool:
+ case Builtin::KindShort:
+ case Builtin::KindInt:
+ case Builtin::KindLong:
+ case Builtin::KindFloat:
+ case Builtin::KindDouble:
+ case Builtin::KindString:
+ case Builtin::KindObjectProxy:
+ {
+ return;
+ }
+ case Builtin::KindObject:
+ case Builtin::KindLocalObject:
+ {
+ break;
+ }
+ }
+
+ break;
+ }
+
+ if(EnumPtr::dynamicCast(newType))
+ {
+ return;
+ }
+
+ if(ProxyPtr::dynamicCast(newType))
+ {
+ return;
+ }
+
+ break;
+ }
+ case Builtin::KindObject:
+ {
+ //
+ // Allow change from Object to class. Validation has to
+ // be done during transformation, when the actual type of
+ // an instance can be compared for compatibility with the
+ // new type.
+ //
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(newType);
+ if(cl || (newb && newb->kind() == Builtin::KindObject))
+ {
+ return;
+ }
+
+ break;
+ }
+ case Builtin::KindObjectProxy:
+ {
+ ProxyPtr p = ProxyPtr::dynamicCast(newType);
+ if(p || (newb && newb->kind() == Builtin::KindObjectProxy) || (newb && newb->kind() == Builtin::KindString))
+ {
+ return;
+ }
+
+ break;
+ }
+ case Builtin::KindLocalObject:
+ {
+ assert(false);
+ break;
+ }
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ ClassDeclPtr cl = ClassDeclPtr::dynamicCast(oldType);
+ if(cl)
+ {
+ //
+ // Allow target type of Object.
+ //
+ BuiltinPtr newb = BuiltinPtr::dynamicCast(newType);
+ if(newb && newb->kind() == Builtin::KindObject)
+ {
+ return;
+ }
+
+ ClassDeclPtr newcl = ClassDeclPtr::dynamicCast(newType);
+ if(newcl && checkClasses(cl, newcl))
+ {
+ return;
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ StructPtr s = StructPtr::dynamicCast(oldType);
+ if(s)
+ {
+ StructPtr news = StructPtr::dynamicCast(newType);
+ if(news && s->scoped() == news->scoped())
+ {
+ return;
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ ProxyPtr proxy = ProxyPtr::dynamicCast(oldType);
+ if(proxy)
+ {
+ //
+ // Allow target type of Object* and string.
+ //
+ BuiltinPtr newb = BuiltinPtr::dynamicCast(newType);
+ if(newb && (newb->kind() == Builtin::KindObjectProxy || newb->kind() == Builtin::KindString))
+ {
+ return;
+ }
+
+ ProxyPtr newProxy = ProxyPtr::dynamicCast(newType);
+ if(newProxy && checkClasses(proxy->_class(), newProxy->_class()))
+ {
+ return;
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ DictionaryPtr dict = DictionaryPtr::dynamicCast(oldType);
+ if(dict)
+ {
+ DictionaryPtr newDict = DictionaryPtr::dynamicCast(newType);
+ if(newDict && dict->scoped() == newDict->scoped())
+ {
+ return;
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ SequencePtr seq = SequencePtr::dynamicCast(oldType);
+ if(seq)
+ {
+ SequencePtr newSeq = SequencePtr::dynamicCast(newType);
+ if(newSeq && seq->scoped() == newSeq->scoped())
+ {
+ return;
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ EnumPtr en = EnumPtr::dynamicCast(oldType);
+ if(en)
+ {
+ EnumPtr newen = EnumPtr::dynamicCast(newType);
+ BuiltinPtr newb = BuiltinPtr::dynamicCast(newType);
+ if((newen && en->scoped() == newen->scoped()) || (newb && newb->kind() == Builtin::KindString))
+ {
+ return;
+ }
+
+ typeChange(desc, oldType, newType);
+ return;
+ }
+
+ assert(false);
+}
+
+void
+Transform::TransformVisitor::typeChange(const string& desc, const TypePtr& t1, const TypePtr& t2)
+{
+ BuiltinPtr b1 = BuiltinPtr::dynamicCast(t1);
+ BuiltinPtr b2 = BuiltinPtr::dynamicCast(t2);
+ ContainedPtr c1 = ContainedPtr::dynamicCast(t1);
+ ContainedPtr c2 = ContainedPtr::dynamicCast(t2);
+
+ if(_ignoreTypeChanges)
+ {
+ _out.nl();
+ _out << "<!-- NOTICE: " << desc << " has changed from ";
+ if(b1)
+ {
+ _out << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ _out << c1->kindOf() << ' ' << c1->scoped();
+ }
+ _out << " to ";
+ if(b2)
+ {
+ _out << b2->kindAsString();
+ }
+ else
+ {
+ assert(c2);
+ _out << c2->kindOf() << ' ' << c2->scoped();
+ }
+ _out << " -->";
+ }
+ else
+ {
+ ostringstream ostr;
+ ostr << "unsupported type change in " << desc << " from ";
+ if(b1)
+ {
+ ostr << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ ostr << c1->kindOf() << ' ' << c1->scoped();
+ }
+ ostr << " to ";
+ if(b2)
+ {
+ ostr << b2->kindAsString();
+ }
+ else
+ {
+ assert(c2);
+ ostr << c2->kindOf() << ' ' << c2->scoped();
+ }
+ _errors.push_back(ostr.str());
+ }
+}
+
+bool
+Transform::TransformVisitor::checkClasses(const ClassDeclPtr& from, const ClassDeclPtr& to)
+{
+ string fromScoped = from->scoped();
+ string toScoped = to->scoped();
+
+ if(fromScoped == toScoped)
+ {
+ return true;
+ }
+
+ //
+ // The types don't match, so check them for compatibility. Specifically,
+ // look up the old type id in the new Slice and see if it has the target
+ // type as a base class.
+ //
+ TypeList l = to->unit()->lookupTypeNoBuiltin(from->scoped(), false);
+ if(!l.empty())
+ {
+ ClassDeclPtr decl = ClassDeclPtr::dynamicCast(l.front());
+ if(decl)
+ {
+ ClassDefPtr def = decl->definition();
+ if(def)
+ {
+ ClassList bases = def->allBases();
+ for(ClassList::iterator p = bases.begin(); p != bases.end(); ++p)
+ {
+ if((*p)->scoped() == toScoped)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+////////////////////////////////////
+// InitVisitor
+////////////////////////////////////
+
+Transform::InitVisitor::InitVisitor(XMLOutput& out, const UnitPtr& oldUnit) :
+ _out(out), _oldUnit(oldUnit)
+{
+}
+
+bool
+Transform::InitVisitor::visitClassDefStart(const ClassDefPtr& v)
+{
+ if(v->isInterface() || v->isLocal())
+ {
+ return false;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _oldUnit->lookupTypeNoBuiltin(scoped, false);
+ if(!l.empty())
+ {
+ ClassDeclPtr decl = ClassDeclPtr::dynamicCast(l.front());
+ if(!decl || decl->isInterface())
+ {
+ BuiltinPtr b1 = BuiltinPtr::dynamicCast(l.front());
+ ContainedPtr c1 = ContainedPtr::dynamicCast(l.front());
+
+ _out.nl();
+ _out << "<!-- NOTICE: " << scoped << " has changed from ";
+ if(b1)
+ {
+ _out << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ _out << c1->kindOf();
+ }
+ _out << " to class";
+ _out << " -->";
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- class " << scoped << " -->";
+ _out << se("init") << attr("type", scoped);
+ _out << ee;
+
+ return false;
+}
+
+bool
+Transform::InitVisitor::visitStructStart(const StructPtr& v)
+{
+ if(v->isLocal())
+ {
+ return false;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _oldUnit->lookupTypeNoBuiltin(scoped, false);
+ if(!l.empty())
+ {
+ StructPtr s = StructPtr::dynamicCast(l.front());
+ if(!s)
+ {
+ BuiltinPtr b1 = BuiltinPtr::dynamicCast(l.front());
+ ContainedPtr c1 = ContainedPtr::dynamicCast(l.front());
+
+ _out.nl();
+ _out << "<!-- NOTICE: " << scoped << " has changed from ";
+ if(b1)
+ {
+ _out << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ _out << c1->kindOf();
+ }
+ _out << " to struct";
+ _out << " -->";
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- struct " << scoped << " -->";
+ _out << se("init") << attr("type", scoped);
+ _out << ee;
+
+ return false;
+}
+
+void
+Transform::InitVisitor::visitSequence(const SequencePtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _oldUnit->lookupTypeNoBuiltin(scoped, false);
+ if(!l.empty())
+ {
+ SequencePtr s = SequencePtr::dynamicCast(l.front());
+ if(!s)
+ {
+ BuiltinPtr b1 = BuiltinPtr::dynamicCast(l.front());
+ ContainedPtr c1 = ContainedPtr::dynamicCast(l.front());
+
+ _out.nl();
+ _out << "<!-- NOTICE: " << scoped << " has changed from ";
+ if(b1)
+ {
+ _out << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ _out << c1->kindOf();
+ }
+ _out << " to sequence";
+ _out << " -->";
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- sequence " << scoped << " -->";
+ _out << se("transform") << attr("type", scoped);
+ _out << ee;
+}
+
+void
+Transform::InitVisitor::visitDictionary(const DictionaryPtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _oldUnit->lookupTypeNoBuiltin(scoped, false);
+ if(!l.empty())
+ {
+ DictionaryPtr d = DictionaryPtr::dynamicCast(l.front());
+ if(!d)
+ {
+ BuiltinPtr b1 = BuiltinPtr::dynamicCast(l.front());
+ ContainedPtr c1 = ContainedPtr::dynamicCast(l.front());
+
+ _out.nl();
+ _out << "<!-- NOTICE: " << scoped << " has changed from ";
+ if(b1)
+ {
+ _out << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ _out << c1->kindOf();
+ }
+ _out << " to dictionary";
+ _out << " -->";
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ _out.nl();
+ _out.nl();
+ _out << "<!-- dictionary " << scoped << " -->";
+ _out << se("init") << attr("type", scoped);
+ _out << ee;
+}
+
+void
+Transform::InitVisitor::visitEnum(const EnumPtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ TypeList l = _oldUnit->lookupTypeNoBuiltin(scoped, false);
+ if(!l.empty())
+ {
+ EnumPtr e = EnumPtr::dynamicCast(l.front());
+ if(!e)
+ {
+ BuiltinPtr b1 = BuiltinPtr::dynamicCast(l.front());
+ ContainedPtr c1 = ContainedPtr::dynamicCast(l.front());
+
+ _out.nl();
+ _out << "<!-- NOTICE: " << scoped << " has changed from ";
+ if(b1)
+ {
+ _out << b1->kindAsString();
+ }
+ else
+ {
+ assert(c1);
+ _out << c1->kindOf();
+ }
+ _out << " to enum";
+ _out << " -->";
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ _out.nl();
+ _out << "<!-- enum " << scoped << " -->";
+ _out << se("init") << attr("type", scoped);
+ _out << ee;
+}
+
+Transform::Analyzer::Analyzer(const UnitPtr& oldUnit, const UnitPtr& newUnit, bool ignoreTypeChanges) :
+ _old(oldUnit), _new(newUnit), _ignoreTypeChanges(ignoreTypeChanges)
+{
+}
+
+void
+Transform::Analyzer::analyze(const TypePtr& oldKey, const TypePtr& newKey, const TypePtr& oldValue,
+ const TypePtr& newValue, ostream& os, vector<string>& missingTypes,
+ vector<string>& errors)
+{
+ XMLOutput out(os);
+
+ out << se("transformer");
+
+ TransformVisitor transformVisitor(out, _new, oldKey, newKey, oldValue, newValue, _ignoreTypeChanges, missingTypes,
+ errors);
+ _old->visit(&transformVisitor);
+
+ InitVisitor initVisitor(out, _old);
+ _new->visit(&initVisitor);
+
+ out << ee;
+ out << '\n';
+}
diff --git a/cpp/src/Transform/Analyzer.h b/cpp/src/Transform/Analyzer.h
new file mode 100644
index 00000000000..3e64ef28153
--- /dev/null
+++ b/cpp/src/Transform/Analyzer.h
@@ -0,0 +1,41 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_ANALYZER_H
+#define TRANSFORM_ANALYZER_H
+
+#include <Slice/Parser.h>
+#include <ostream>
+
+namespace Transform
+{
+
+class Analyzer
+{
+public:
+
+ Analyzer(const Slice::UnitPtr&, const Slice::UnitPtr&, bool);
+ void analyze(const Slice::TypePtr&, const Slice::TypePtr&, const Slice::TypePtr&, const Slice::TypePtr&,
+ std::ostream&, std::vector<std::string>&, std::vector<std::string>&);
+
+private:
+
+ Slice::UnitPtr _old;
+ Slice::UnitPtr _new;
+ bool _ignoreTypeChanges;
+};
+
+}
+
+#endif
diff --git a/cpp/src/Transform/Data.cpp b/cpp/src/Transform/Data.cpp
new file mode 100644
index 00000000000..0b62d6f0b5f
--- /dev/null
+++ b/cpp/src/Transform/Data.cpp
@@ -0,0 +1,3458 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Data.h>
+#include <Transform/TransformUtil.h>
+#include <IceUtil/InputUtil.h>
+
+using namespace std;
+using namespace IceUtil;
+
+namespace Transform
+{
+
+//
+// ObjectWriter
+//
+class ObjectWriter : public Ice::Object
+{
+public:
+
+ ObjectWriter(const ObjectDataPtr&);
+
+ virtual void __write(IceInternal::BasicStream*, bool) const;
+ virtual void __read(IceInternal::BasicStream*, bool = true);
+
+private:
+
+ ObjectDataPtr _value;
+};
+
+//
+// ObjectReader
+//
+class ObjectReader : public Ice::Object
+{
+public:
+
+ ObjectReader(const DataFactoryPtr&, const Slice::TypePtr&);
+
+ virtual void __write(IceInternal::BasicStream*) const;
+ virtual void __read(IceInternal::BasicStream*, bool = true);
+
+ ObjectDataPtr getValue() const;
+
+private:
+
+ DataFactoryPtr _factory;
+ Slice::TypePtr _type;
+ ObjectDataPtr _value;
+};
+typedef IceUtil::Handle<ObjectReader> ObjectReaderPtr;
+
+} // End of namespace Transform
+
+//
+// ObjectWriter
+//
+Transform::ObjectWriter::ObjectWriter(const ObjectDataPtr& value) :
+ _value(value)
+{
+}
+
+void
+Transform::ObjectWriter::__write(IceInternal::BasicStream* os, bool) const
+{
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(_value->_type);
+ Slice::ClassDefPtr type;
+ if(decl)
+ {
+ type = decl->definition();
+ }
+ while(type)
+ {
+ os->writeTypeId(type->scoped());
+ os->startWriteSlice();
+ Slice::DataMemberList members = type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = _value->_members.find((*p)->name());
+ assert(q != _value->_members.end());
+ q->second->marshal(*os);
+ }
+ os->endWriteSlice();
+
+ Slice::ClassList bases = type->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ type = bases.front();
+ }
+ else
+ {
+ type = 0;
+ }
+ }
+
+ //
+ // Ice::Object slice
+ //
+ os->writeTypeId(Ice::Object::ice_staticId());
+ os->startWriteSlice();
+ _value->_facetMap->marshal(*os);
+ os->endWriteSlice();
+}
+
+void
+Transform::ObjectWriter::__read(IceInternal::BasicStream*, bool)
+{
+ assert(false);
+}
+
+//
+// ObjectReader
+//
+Transform::ObjectReader::ObjectReader(const DataFactoryPtr& factory, const Slice::TypePtr& type) :
+ _factory(factory), _type(type)
+{
+}
+
+void
+Transform::ObjectReader::__write(IceInternal::BasicStream*) const
+{
+ assert(false);
+}
+
+void
+Transform::ObjectReader::__read(IceInternal::BasicStream* is, bool rid)
+{
+ const_cast<ObjectDataPtr&>(_value) = new ObjectData(_factory, _type, true);
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(_type);
+ Slice::ClassDefPtr type;
+ if(decl)
+ {
+ type = decl->definition();
+ }
+ while(type)
+ {
+ if(rid)
+ {
+ string id;
+ is->readTypeId(id);
+ assert(id == type->scoped());
+ }
+
+ is->startReadSlice();
+ Slice::DataMemberList members = type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::iterator q = _value->_members.find((*p)->name());
+ assert(q != _value->_members.end());
+ q->second->unmarshal(*is);
+ }
+ is->endReadSlice();
+
+ Slice::ClassList bases = type->bases();
+ if(!bases.empty() && !bases.front()->isInterface())
+ {
+ type = bases.front();
+ }
+ else
+ {
+ type = 0;
+ }
+
+ rid = true;
+ }
+
+ //
+ // Ice::Object slice
+ //
+ if(rid)
+ {
+ string id;
+ is->readTypeId(id);
+ assert(id == Ice::Object::ice_staticId());
+ }
+ is->startReadSlice();
+ _value->_facetMap->unmarshal(*is);
+ is->endReadSlice();
+}
+
+Transform::ObjectDataPtr
+Transform::ObjectReader::getValue() const
+{
+ return _value;
+}
+
+//
+// DataInterceptor
+//
+Transform::DataInterceptor::~DataInterceptor()
+{
+}
+
+//
+// DataInitializer
+//
+Transform::DataInitializer::~DataInitializer()
+{
+}
+
+//
+// DataFactory
+//
+Transform::DataFactory::DataFactory(const Ice::CommunicatorPtr& communicator, const Slice::UnitPtr& unit,
+ const ErrorReporterPtr& errorReporter) :
+ _communicator(communicator), _unit(unit), _errorReporter(errorReporter), _initializersEnabled(true)
+{
+}
+
+Transform::DataPtr
+Transform::DataFactory::create(const Slice::TypePtr& type, bool readOnly)
+{
+ DataPtr data = createImpl(type, readOnly);
+ if(_initializersEnabled && !readOnly)
+ {
+ string name = typeName(type);
+ InitMap::iterator p = _initializers.find(name);
+ if(p != _initializers.end())
+ {
+ p->second->initialize(this, data, _communicator);
+ }
+ }
+ return data;
+}
+
+Transform::DataPtr
+Transform::DataFactory::createBoolean(bool b, bool readOnly)
+{
+ return new BooleanData(getBuiltin(Slice::Builtin::KindBool), _errorReporter, readOnly, b);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createInteger(Ice::Long i, bool readOnly)
+{
+ return new IntegerData(getBuiltin(Slice::Builtin::KindLong), _errorReporter, readOnly, i);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createDouble(double d, bool readOnly)
+{
+ return new DoubleData(getBuiltin(Slice::Builtin::KindDouble), _errorReporter, readOnly, d);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createString(const string& s, bool readOnly)
+{
+ return new StringData(this, getBuiltin(Slice::Builtin::KindString), _errorReporter, readOnly, s);
+}
+
+Transform::DataPtr
+Transform::DataFactory::createNil(bool readOnly)
+{
+ return new ObjectRef(this, getBuiltin(Slice::Builtin::KindObject), readOnly);
+}
+
+Slice::BuiltinPtr
+Transform::DataFactory::getBuiltin(Slice::Builtin::Kind kind) const
+{
+ return _unit->builtin(kind);
+}
+
+void
+Transform::DataFactory::addInitializer(const string& type, const DataInitializerPtr& init)
+{
+ _initializers.insert(InitMap::value_type(type, init));
+}
+
+void
+Transform::DataFactory::enableInitializers()
+{
+ _initializersEnabled = true;
+}
+
+void
+Transform::DataFactory::disableInitializers()
+{
+ _initializersEnabled = false;
+}
+
+Transform::ErrorReporterPtr
+Transform::DataFactory::getErrorReporter() const
+{
+ return _errorReporter;
+}
+
+Transform::DataPtr
+Transform::DataFactory::createImpl(const Slice::TypePtr& type, bool readOnly)
+{
+ Slice::BuiltinPtr builtin = Slice::BuiltinPtr::dynamicCast(type);
+ if(builtin)
+ {
+ switch(builtin->kind())
+ {
+ case Slice::Builtin::KindBool:
+ return new BooleanData(builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ return new IntegerData(builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ return new DoubleData(builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindString:
+ return new StringData(this, builtin, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindObject:
+ return new ObjectRef(this, builtin, readOnly);
+
+ case Slice::Builtin::KindObjectProxy:
+ return new ProxyData(builtin, _communicator, _errorReporter, readOnly);
+
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ return 0;
+ }
+ }
+
+ Slice::SequencePtr seq = Slice::SequencePtr::dynamicCast(type);
+ if(seq)
+ {
+ return new SequenceData(this, seq, _errorReporter, readOnly);
+ }
+
+ Slice::ProxyPtr proxy = Slice::ProxyPtr::dynamicCast(type);
+ if(proxy)
+ {
+ return new ProxyData(proxy, _communicator, _errorReporter, readOnly);
+ }
+
+ Slice::StructPtr st = Slice::StructPtr::dynamicCast(type);
+ if(st)
+ {
+ return new StructData(this, st, _errorReporter, readOnly);
+ }
+
+ Slice::EnumPtr en = Slice::EnumPtr::dynamicCast(type);
+ if(en)
+ {
+ return new EnumData(en, _errorReporter, readOnly);
+ }
+
+ Slice::DictionaryPtr dict = Slice::DictionaryPtr::dynamicCast(type);
+ if(dict)
+ {
+ return new DictionaryData(this, dict, _errorReporter, readOnly);
+ }
+
+ Slice::ClassDeclPtr cl = Slice::ClassDeclPtr::dynamicCast(type);
+ if(cl)
+ {
+ Slice::ClassDefPtr def = cl->definition();
+ if(!def)
+ {
+ _errorReporter->error("class " + cl->scoped() + " declared but not defined");
+ }
+ return new ObjectRef(this, cl, readOnly);
+ }
+
+ return 0;
+}
+
+//
+// Data
+//
+Transform::Data::Data(const ErrorReporterPtr& errorReporter, bool readOnly) :
+ _errorReporter(errorReporter), _readOnly(readOnly)
+{
+}
+
+Transform::Data::~Data()
+{
+}
+
+bool
+Transform::Data::readOnly() const
+{
+ return _readOnly;
+}
+
+void
+Transform::Data::print(ostream& os) const
+{
+ ObjectDataHistory history;
+ IceUtil::Output out(os);
+ printI(out, history);
+}
+
+bool
+Transform::Data::isCompatible(const Slice::TypePtr& dest, const Slice::TypePtr& src)
+{
+ Slice::BuiltinPtr b1 = Slice::BuiltinPtr::dynamicCast(dest);
+ if(b1)
+ {
+ Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src);
+ switch(b1->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ {
+ if(b2)
+ {
+ switch(b2->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindString:
+ {
+ return true;
+ }
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ {
+ return false;
+ }
+ }
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindBool:
+ {
+ if(b2 && (b2->kind() == Slice::Builtin::KindBool || b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ {
+ if(b2)
+ {
+ switch(b2->kind())
+ {
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ {
+ return true;
+ }
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ {
+ return false;
+ }
+ }
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindString:
+ {
+ if(b2)
+ {
+ switch(b2->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObjectProxy:
+ {
+ return true;
+ }
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindLocalObject:
+ {
+ return false;
+ }
+ }
+
+ return false;
+ }
+ else if(Slice::EnumPtr::dynamicCast(src))
+ {
+ return true;
+ }
+ else if(Slice::ProxyPtr::dynamicCast(src))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindObject:
+ {
+ //
+ // Allow transformation from Object to class. Validation has to
+ // be done during transformation, when the actual type of
+ // an instance can be compared for compatibility with the
+ // new type.
+ //
+ Slice::ClassDeclPtr cl = Slice::ClassDeclPtr::dynamicCast(src);
+ if(cl || (b2 && b2->kind() == Slice::Builtin::KindObject))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindObjectProxy:
+ {
+ Slice::ProxyPtr p = Slice::ProxyPtr::dynamicCast(src);
+ if(p || (b2 && b2->kind() == Slice::Builtin::KindObjectProxy) ||
+ (b2 && b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ case Slice::Builtin::KindLocalObject:
+ {
+ assert(false);
+ return false;
+ }
+ }
+
+ assert(false);
+ }
+
+ Slice::ClassDeclPtr cl1 = Slice::ClassDeclPtr::dynamicCast(dest);
+ if(cl1)
+ {
+ Slice::ClassDeclPtr cl2 = Slice::ClassDeclPtr::dynamicCast(src);
+ if(cl2 && checkClasses(cl1, cl2))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ Slice::StructPtr s1 = Slice::StructPtr::dynamicCast(dest);
+ if(s1)
+ {
+ Slice::StructPtr s2 = Slice::StructPtr::dynamicCast(src);
+ if(s2 && s1->scoped() == s2->scoped())
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ Slice::ProxyPtr p1 = Slice::ProxyPtr::dynamicCast(dest);
+ if(p1)
+ {
+ Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src);
+ if(b2 && (b2->kind() == Slice::Builtin::KindObjectProxy || b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ Slice::ProxyPtr p2 = Slice::ProxyPtr::dynamicCast(src);
+ if(p2 && checkClasses(p1->_class(), p2->_class()))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ Slice::DictionaryPtr d1 = Slice::DictionaryPtr::dynamicCast(dest);
+ if(d1)
+ {
+ Slice::DictionaryPtr d2 = Slice::DictionaryPtr::dynamicCast(src);
+ if(d2)
+ {
+ return isCompatible(d1->keyType(), d2->keyType()) && isCompatible(d1->valueType(), d2->valueType());
+ }
+
+ return false;
+ }
+
+ Slice::SequencePtr seq1 = Slice::SequencePtr::dynamicCast(dest);
+ if(seq1)
+ {
+ Slice::SequencePtr seq2 = Slice::SequencePtr::dynamicCast(src);
+ if(seq2)
+ {
+ return isCompatible(seq1->type(), seq2->type());
+ }
+
+ return false;
+ }
+
+ Slice::EnumPtr e1 = Slice::EnumPtr::dynamicCast(dest);
+ if(e1)
+ {
+ Slice::EnumPtr e2 = Slice::EnumPtr::dynamicCast(src);
+ Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src);
+ if((e2 && e1->scoped() == e2->scoped()) || (b2 && b2->kind() == Slice::Builtin::KindString))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ assert(false);
+ return false;
+}
+
+bool
+Transform::Data::checkClasses(const Slice::ClassDeclPtr& dest, const Slice::ClassDeclPtr& src)
+{
+ string s1 = dest->scoped();
+ string s2 = src->scoped();
+ if(s1 == s2)
+ {
+ return true;
+ }
+ else
+ {
+ Slice::ClassDefPtr def = src->definition();
+ if(!def)
+ {
+ _errorReporter->error("class " + s2 + " declared but not defined");
+ }
+ Slice::ClassList bases = def->allBases();
+ for(Slice::ClassList::iterator p = bases.begin(); p != bases.end(); ++p)
+ {
+ if((*p)->scoped() == s1)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//
+// PrimitiveData
+//
+Transform::PrimitiveData::PrimitiveData(const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly)
+{
+}
+
+Transform::DataPtr
+Transform::PrimitiveData::getMember(const string&) const
+{
+ return 0;
+}
+
+Transform::DataPtr
+Transform::PrimitiveData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of primitive value");
+ return 0;
+}
+
+void
+Transform::PrimitiveData::registerObjects(ObjectDataMap&) const
+{
+}
+
+void
+Transform::PrimitiveData::destroy()
+{
+}
+
+//
+// BooleanData
+//
+Transform::BooleanData::BooleanData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(false)
+{
+}
+
+Transform::BooleanData::BooleanData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly, bool value) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(value)
+{
+}
+
+bool
+Transform::BooleanData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::BooleanData::operator!=(const Data& rhs) const
+{
+ const BooleanData* b = dynamic_cast<const BooleanData*>(&rhs);
+ if(!b)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != b->_value;
+}
+
+bool
+Transform::BooleanData::operator<(const Data& rhs) const
+{
+ const BooleanData* b = dynamic_cast<const BooleanData*>(&rhs);
+ if(!b)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < b->_value;
+}
+
+void
+Transform::BooleanData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ BooleanDataPtr b = BooleanDataPtr::dynamicCast(data);
+ if(b)
+ {
+ _value = b->booleanValue();
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::BooleanData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ StringDataPtr s = StringDataPtr::dynamicCast(value);
+ if(convert && s)
+ {
+ string v = s->stringValue();
+ if(v == "true")
+ {
+ _value = true;
+ }
+ else if(v == "false")
+ {
+ _value = false;
+ }
+ else
+ {
+ _errorReporter->conversionError(v, _type);
+ }
+ }
+ else
+ {
+ _value = value->booleanValue(convert);
+ }
+}
+
+Transform::DataPtr
+Transform::BooleanData::clone() const
+{
+ return new BooleanData(_type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::BooleanData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::BooleanData::marshal(IceInternal::BasicStream& os) const
+{
+ os.write(_value);
+}
+
+void
+Transform::BooleanData::unmarshal(IceInternal::BasicStream& is)
+{
+ is.read(_value);
+}
+
+bool
+Transform::BooleanData::booleanValue(bool) const
+{
+ return _value;
+}
+
+Ice::Long
+Transform::BooleanData::integerValue(bool) const
+{
+ _errorReporter->error("boolean cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::BooleanData::doubleValue(bool) const
+{
+ _errorReporter->error("boolean cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::BooleanData::stringValue(bool convert) const
+{
+ if(convert)
+ {
+ return toString();
+ }
+ else
+ {
+ return string();
+ }
+}
+
+string
+Transform::BooleanData::toString() const
+{
+ return (_value ? "true" : "false");
+}
+
+void
+Transform::BooleanData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "bool(" << toString() << ")";
+}
+
+//
+// IntegerData
+//
+Transform::IntegerData::IntegerData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(0)
+{
+}
+
+Transform::IntegerData::IntegerData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly, Ice::Long value) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(value)
+{
+}
+
+bool
+Transform::IntegerData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::IntegerData::operator!=(const Data& rhs) const
+{
+ const IntegerData* i = dynamic_cast<const IntegerData*>(&rhs);
+ if(!i)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != i->_value;
+}
+
+bool
+Transform::IntegerData::operator<(const Data& rhs) const
+{
+ const IntegerData* i = dynamic_cast<const IntegerData*>(&rhs);
+ if(!i)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < i->_value;
+}
+
+void
+Transform::IntegerData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ Ice::Long value;
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(i)
+ {
+ value = i->_value;
+ }
+ else if(s)
+ {
+ string str = s->stringValue();
+ string::size_type pos;
+ if(!IceUtil::stringToInt64(str, value, pos))
+ {
+ _errorReporter->conversionError(str, _type);
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+
+ if(rangeCheck(value))
+ {
+ _value = value;
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::IntegerData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ _value = value->integerValue(convert);
+}
+
+Transform::DataPtr
+Transform::IntegerData::clone() const
+{
+ return new IntegerData(_type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::IntegerData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::IntegerData::marshal(IceInternal::BasicStream& os) const
+{
+ rangeCheck(_value);
+
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindByte:
+ {
+ os.write(static_cast<Ice::Byte>(_value));
+ break;
+ }
+ case Slice::Builtin::KindShort:
+ {
+ os.write(static_cast<Ice::Short>(_value));
+ break;
+ }
+ case Slice::Builtin::KindInt:
+ {
+ os.write(static_cast<Ice::Int>(_value));
+ break;
+ }
+ case Slice::Builtin::KindLong:
+ {
+ os.write(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+void
+Transform::IntegerData::unmarshal(IceInternal::BasicStream& is)
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindByte:
+ {
+ Ice::Byte val;
+ is.read(val);
+ _value = val & 0xff;
+ break;
+ }
+ case Slice::Builtin::KindShort:
+ {
+ Ice::Short val;
+ is.read(val);
+ _value = val;
+ break;
+ }
+ case Slice::Builtin::KindInt:
+ {
+ Ice::Int val;
+ is.read(val);
+ _value = val;
+ break;
+ }
+ case Slice::Builtin::KindLong:
+ {
+ is.read(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+bool
+Transform::IntegerData::booleanValue(bool) const
+{
+ _errorReporter->error("integer cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::IntegerData::integerValue(bool) const
+{
+ return _value;
+}
+
+double
+Transform::IntegerData::doubleValue(bool convert) const
+{
+ if(convert)
+ {
+ return _value;
+ }
+ else
+ {
+ _errorReporter->error("integer cannot be converted to double");
+ return 0;
+ }
+}
+
+string
+Transform::IntegerData::stringValue(bool convert) const
+{
+ if(convert)
+ {
+ return toString();
+ }
+ else
+ {
+ _errorReporter->error("integer cannot be converted to string");
+ return string();
+ }
+}
+
+string
+Transform::IntegerData::toString() const
+{
+ return toString(_value);
+}
+
+bool
+Transform::IntegerData::rangeCheck(Ice::Long value) const
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindByte:
+ {
+ if(value < 0 || value > 255)
+ {
+ _errorReporter->rangeError(toString(value), _type);
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindShort:
+ {
+ if(value < SHRT_MIN || value > SHRT_MAX)
+ {
+ _errorReporter->rangeError(toString(value), _type);
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindInt:
+ {
+ if(value < INT_MIN || value > INT_MAX)
+ {
+ _errorReporter->rangeError(toString(value), _type);
+ }
+ else
+ {
+ return true;
+ }
+ break;
+ }
+
+ case Slice::Builtin::KindLong:
+ {
+ return true;
+ }
+
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+
+ return false;
+}
+
+string
+Transform::IntegerData::toString(Ice::Long value)
+{
+ char buf[64];
+#ifdef WIN32
+ sprintf(buf, "%I64d", value);
+#else
+ sprintf(buf, "%lld", value);
+#endif
+ return string(buf);
+}
+
+void
+Transform::IntegerData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "integer(" << toString() << ")";
+}
+
+//
+// DoubleData
+//
+Transform::DoubleData::DoubleData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(0)
+{
+}
+
+Transform::DoubleData::DoubleData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter,
+ bool readOnly, double value) :
+ PrimitiveData(errorReporter, readOnly), _type(type), _value(value)
+{
+}
+
+bool
+Transform::DoubleData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::DoubleData::operator!=(const Data& rhs) const
+{
+ const DoubleData* d = dynamic_cast<const DoubleData*>(&rhs);
+ if(!d)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != d->_value;
+}
+
+bool
+Transform::DoubleData::operator<(const Data& rhs) const
+{
+ const DoubleData* d = dynamic_cast<const DoubleData*>(&rhs);
+ if(!d)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < d->_value;
+}
+
+void
+Transform::DoubleData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ DoubleDataPtr d = DoubleDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(d)
+ {
+ _value = d->doubleValue();
+ }
+ else if(s)
+ {
+ string str = s->stringValue();
+ const char* start = str.c_str();
+ char* end;
+ double v = strtod(start, &end);
+ if(errno == ERANGE)
+ {
+ _errorReporter->rangeError(str, _type);
+ }
+ else
+ {
+ while(*end)
+ {
+ if(!isspace(*end))
+ {
+ _errorReporter->conversionError(str, _type);
+ break;
+ }
+ end++;
+ }
+ if(!*end)
+ {
+ _value = v;
+ }
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::DoubleData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ _value = value->doubleValue(convert);
+}
+
+Transform::DataPtr
+Transform::DoubleData::clone() const
+{
+ return new DoubleData(_type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::DoubleData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::DoubleData::marshal(IceInternal::BasicStream& os) const
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindFloat:
+ {
+ os.write(static_cast<Ice::Float>(_value));
+ break;
+ }
+ case Slice::Builtin::KindDouble:
+ {
+ os.write(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+void
+Transform::DoubleData::unmarshal(IceInternal::BasicStream& is)
+{
+ switch(_type->kind())
+ {
+ case Slice::Builtin::KindFloat:
+ {
+ Ice::Float val;
+ is.read(val);
+ _value = val;
+ break;
+ }
+ case Slice::Builtin::KindDouble:
+ {
+ is.read(_value);
+ break;
+ }
+
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ case Slice::Builtin::KindBool:
+ case Slice::Builtin::KindString:
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+}
+
+bool
+Transform::DoubleData::booleanValue(bool) const
+{
+ _errorReporter->error("double cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::DoubleData::integerValue(bool convert) const
+{
+ if(convert)
+ {
+ return static_cast<Ice::Long>(_value);
+ }
+ else
+ {
+ _errorReporter->error("double cannot be converted to integer");
+ return 0;
+ }
+}
+
+double
+Transform::DoubleData::doubleValue(bool) const
+{
+ return _value;
+}
+
+string
+Transform::DoubleData::stringValue(bool convert) const
+{
+ if(convert)
+ {
+ return toString();
+ }
+ else
+ {
+ _errorReporter->error("double cannot be converted to string");
+ return string();
+ }
+}
+
+string
+Transform::DoubleData::toString() const
+{
+ char buff[64];
+ sprintf(buff, "%g", _value);
+ return string(buff);
+}
+
+void
+Transform::DoubleData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "double(" << toString() << ")";
+}
+
+//
+// StringData
+//
+Transform::StringData::StringData(const DataFactoryPtr& factory, const Slice::BuiltinPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ PrimitiveData(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ setValue("");
+}
+
+Transform::StringData::StringData(const DataFactoryPtr& factory, const Slice::BuiltinPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const string& value) :
+ PrimitiveData(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ setValue(value);
+}
+
+Transform::DataPtr
+Transform::StringData::getMember(const string& member) const
+{
+ if(member == "length")
+ {
+ return _length;
+ }
+
+ return 0;
+}
+
+bool
+Transform::StringData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::StringData::operator!=(const Data& rhs) const
+{
+ const StringData* s = dynamic_cast<const StringData*>(&rhs);
+ if(!s)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != s->_value;
+}
+
+bool
+Transform::StringData::operator<(const Data& rhs) const
+{
+ const StringData* s = dynamic_cast<const StringData*>(&rhs);
+ if(!s)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < s->_value;
+}
+
+void
+Transform::StringData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ BooleanDataPtr b = BooleanDataPtr::dynamicCast(data);
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(data);
+ DoubleDataPtr d = DoubleDataPtr::dynamicCast(data);
+ EnumDataPtr e = EnumDataPtr::dynamicCast(data);
+ ProxyDataPtr p = ProxyDataPtr::dynamicCast(data);
+ if(s || b || i || d || e || p)
+ {
+ setValue(data->toString());
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::StringData::set(const DataPtr& value, DataInterceptor&, bool convert)
+{
+ setValue(value->stringValue(convert));
+}
+
+Transform::DataPtr
+Transform::StringData::clone() const
+{
+ return new StringData(_factory, _type, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::StringData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::StringData::marshal(IceInternal::BasicStream& os) const
+{
+ os.write(_value);
+}
+
+void
+Transform::StringData::unmarshal(IceInternal::BasicStream& is)
+{
+ string s;
+ is.read(s);
+ setValue(s);
+}
+
+bool
+Transform::StringData::booleanValue(bool) const
+{
+ _errorReporter->error("string cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::StringData::integerValue(bool) const
+{
+ _errorReporter->error("string cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::StringData::doubleValue(bool) const
+{
+ _errorReporter->error("string cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::StringData::stringValue(bool) const
+{
+ return _value;
+}
+
+string
+Transform::StringData::toString() const
+{
+ return _value;
+}
+
+void
+Transform::StringData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << "'" << toString() << "'";
+}
+
+void
+Transform::StringData::setValue(const string& value)
+{
+ _value = value;
+ _length = _factory->createInteger(static_cast<Ice::Long>(_value.size()), true);
+}
+
+//
+// ProxyData
+//
+Transform::ProxyData::ProxyData(const Slice::TypePtr& type, const Ice::CommunicatorPtr& communicator,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _type(type), _communicator(communicator)
+{
+}
+
+Transform::ProxyData::ProxyData(const Slice::TypePtr& type, const Ice::CommunicatorPtr& communicator,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const Ice::ObjectPrx& value) :
+ Data(errorReporter, readOnly), _type(type), _communicator(communicator), _value(value)
+{
+}
+
+Transform::DataPtr
+Transform::ProxyData::getMember(const string& member) const
+{
+ // TODO: Support members (id, facet, etc.)?
+#if 0
+ if(member == "length")
+ {
+ return new IntegerData(_value.length());
+ }
+#endif
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::ProxyData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of proxy value");
+ return 0;
+}
+
+bool
+Transform::ProxyData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::ProxyData::operator!=(const Data& rhs) const
+{
+ const ProxyData* p = dynamic_cast<const ProxyData*>(&rhs);
+ if(!p)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != p->_value;
+}
+
+bool
+Transform::ProxyData::operator<(const Data& rhs) const
+{
+ const ProxyData* p = dynamic_cast<const ProxyData*>(&rhs);
+ if(!p)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < p->_value;
+}
+
+void
+Transform::ProxyData::registerObjects(ObjectDataMap&) const
+{
+}
+
+void
+Transform::ProxyData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::ProxyData::set(const DataPtr& value, DataInterceptor&, bool)
+{
+ transformI(value);
+}
+
+Transform::DataPtr
+Transform::ProxyData::clone() const
+{
+ return new ProxyData(_type, _communicator, _errorReporter, _readOnly, _value);
+}
+
+Slice::TypePtr
+Transform::ProxyData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::ProxyData::destroy()
+{
+}
+
+void
+Transform::ProxyData::marshal(IceInternal::BasicStream& os) const
+{
+ os.write(_value);
+}
+
+void
+Transform::ProxyData::unmarshal(IceInternal::BasicStream& is)
+{
+ is.read(_value);
+}
+
+bool
+Transform::ProxyData::booleanValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::ProxyData::integerValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::ProxyData::doubleValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::ProxyData::stringValue(bool) const
+{
+ _errorReporter->error("proxy cannot be converted to string");
+ return string();
+}
+
+string
+Transform::ProxyData::toString() const
+{
+ if(_value && _str.empty())
+ {
+ const_cast<string&>(_str) = _communicator->proxyToString(_value);
+ }
+ return _str;
+}
+
+Ice::ObjectPrx
+Transform::ProxyData::getValue() const
+{
+ return _value;
+}
+
+void
+Transform::ProxyData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << typeName(_type) << "*(" << toString() << ")";
+}
+
+void
+Transform::ProxyData::transformI(const DataPtr& data)
+{
+ ProxyDataPtr p = ProxyDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(p)
+ {
+ _value = p->getValue();
+ _str.clear();
+ }
+ else if(s)
+ {
+ setValue(s->stringValue());
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+void
+Transform::ProxyData::setValue(const string& str)
+{
+ try
+ {
+ _value = _communicator->stringToProxy(str);
+ _str = str;
+ }
+ catch(const Ice::LocalException&)
+ {
+ _errorReporter->conversionError(str, _type);
+ }
+}
+
+//
+// StructData
+//
+Transform::StructData::StructData(const DataFactoryPtr& factory, const Slice::StructPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _type(type)
+{
+ Slice::DataMemberList members = type->dataMembers();
+ for(Slice::DataMemberList::iterator q = members.begin(); q != members.end(); ++q)
+ {
+ DataPtr value = factory->create((*q)->type(), _readOnly);
+ assert(value);
+ _members[(*q)->name()] = value;
+ }
+}
+
+Transform::StructData::StructData(const Slice::StructPtr& type, const ErrorReporterPtr& errorReporter, bool readOnly,
+ const DataMemberMap& members) :
+ Data(errorReporter, readOnly), _type(type)
+{
+ for(DataMemberMap::const_iterator p = members.begin(); p != members.end(); ++p)
+ {
+ _members[p->first] = p->second->clone();
+ }
+}
+
+Transform::DataPtr
+Transform::StructData::getMember(const string& member) const
+{
+ DataMemberMap::const_iterator p = _members.find(member);
+ if(p != _members.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::StructData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of struct value");
+ return 0;
+}
+
+bool
+Transform::StructData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::StructData::operator!=(const Data& rhs) const
+{
+ const StructData* s = dynamic_cast<const StructData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ assert(_members.size() == s->_members.size());
+
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = s->_members.find(p->first);
+ assert(q != s->_members.end());
+
+ if(p->second != q->second)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+Transform::StructData::operator<(const Data& rhs) const
+{
+ const StructData* s = dynamic_cast<const StructData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ assert(_members.size() == s->_members.size());
+
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = s->_members.find(p->first);
+ assert(q != s->_members.end());
+
+ if(p->second < q->second)
+ {
+ return true;
+ }
+ else if(q->second < p->second)
+ {
+ return false;
+ }
+ }
+
+ return false;
+}
+
+void
+Transform::StructData::registerObjects(ObjectDataMap& map) const
+{
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ p->second->registerObjects(map);
+ }
+}
+
+void
+Transform::StructData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::StructData::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::StructData::clone() const
+{
+ return new StructData(_type, _errorReporter, _readOnly, _members);
+}
+
+Slice::TypePtr
+Transform::StructData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::StructData::destroy()
+{
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ p->second->destroy();
+ }
+}
+
+void
+Transform::StructData::marshal(IceInternal::BasicStream& os) const
+{
+ Slice::DataMemberList members = _type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = _members.find((*p)->name());
+ assert(q != _members.end());
+ q->second->marshal(os);
+ }
+}
+
+void
+Transform::StructData::unmarshal(IceInternal::BasicStream& is)
+{
+ Slice::DataMemberList members = _type->dataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ DataMemberMap::const_iterator q = _members.find((*p)->name());
+ assert(q != _members.end());
+ q->second->unmarshal(is);
+ }
+}
+
+bool
+Transform::StructData::booleanValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::StructData::integerValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::StructData::doubleValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::StructData::stringValue(bool) const
+{
+ _errorReporter->error("struct " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::StructData::toString() const
+{
+ return stringValue();
+}
+
+Transform::DataMemberMap
+Transform::StructData::getMembers() const
+{
+ return _members;
+}
+
+void
+Transform::StructData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "struct " << typeName(_type);
+ out << sb;
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ out << nl;
+ out << p->first << " = ";
+ p->second->printI(out, history);
+ }
+ out << eb;
+}
+
+void
+Transform::StructData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ StructDataPtr s = StructDataPtr::dynamicCast(data);
+ if(s && _type->scoped() == s->_type->scoped())
+ {
+ //
+ // Invoke transform() on members with the same name.
+ //
+ for(DataMemberMap::iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::iterator q = s->_members.find(p->first);
+ if(q != s->_members.end())
+ {
+ p->second->transform(q->second, interceptor);
+ }
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+//
+// SequenceData
+//
+Transform::SequenceData::SequenceData(const DataFactoryPtr& factory, const Slice::SequencePtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ _length = _factory->createInteger(0, true);
+}
+
+Transform::SequenceData::SequenceData(const DataFactoryPtr& factory, const Slice::SequencePtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const DataList& elements) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ for(DataList::const_iterator p = elements.begin(); p != elements.end(); ++p)
+ {
+ _elements.push_back((*p)->clone());
+ }
+ _length = _factory->createInteger(static_cast<Ice::Long>(_elements.size()), true);
+}
+
+Transform::DataPtr
+Transform::SequenceData::getMember(const string& member) const
+{
+ if(member == "length")
+ {
+ return _length;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::SequenceData::getElement(const DataPtr& element) const
+{
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(element);
+ if(!i)
+ {
+ _errorReporter->error("invalid sequence index type " + typeName(element->getType()));
+ }
+
+ Ice::Long iv = i->integerValue();
+ if(iv < 0 || iv >= _elements.size())
+ {
+ _errorReporter->error("sequence index " + i->toString() + " out of range");
+ }
+
+ return _elements[static_cast<DataList::size_type>(iv)];
+}
+
+bool
+Transform::SequenceData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::SequenceData::operator!=(const Data& rhs) const
+{
+ const SequenceData* s = dynamic_cast<const SequenceData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _elements != s->_elements;
+}
+
+bool
+Transform::SequenceData::operator<(const Data& rhs) const
+{
+ const SequenceData* s = dynamic_cast<const SequenceData*>(&rhs);
+ if(!s || _type->scoped() != s->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _elements < s->_elements;
+}
+
+void
+Transform::SequenceData::registerObjects(ObjectDataMap& map) const
+{
+ if(_type->type()->usesClasses())
+ {
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p)
+ {
+ (*p)->registerObjects(map);
+ }
+ }
+}
+
+void
+Transform::SequenceData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::SequenceData::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::SequenceData::clone() const
+{
+ return new SequenceData(_factory, _type, _errorReporter, _readOnly, _elements);
+}
+
+Slice::TypePtr
+Transform::SequenceData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::SequenceData::destroy()
+{
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p)
+ {
+ (*p)->destroy();
+ }
+}
+
+void
+Transform::SequenceData::marshal(IceInternal::BasicStream& os) const
+{
+ os.writeSize(_elements.size());
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p)
+ {
+ (*p)->marshal(os);
+ }
+}
+
+void
+Transform::SequenceData::unmarshal(IceInternal::BasicStream& is)
+{
+ Slice::TypePtr type = _type->type();
+ Ice::Int sz;
+ is.readSize(sz);
+ _elements.reserve(sz);
+ for(Ice::Int i = 0; i < sz; ++i)
+ {
+ DataPtr v = _factory->create(type, _readOnly);
+ v->unmarshal(is);
+ _elements.push_back(v);
+ }
+ _length = _factory->createInteger(sz, true);
+}
+
+bool
+Transform::SequenceData::booleanValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::SequenceData::integerValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::SequenceData::doubleValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::SequenceData::stringValue(bool) const
+{
+ _errorReporter->error("sequence " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::SequenceData::toString() const
+{
+ return stringValue();
+}
+
+Transform::DataList
+Transform::SequenceData::getElements() const
+{
+ return _elements;
+}
+
+void
+Transform::SequenceData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "sequence " << typeName(_type) << " (size = " << _elements.size() << ")";
+ out << sb;
+ Ice::Int i = 0;
+ for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p, ++i)
+ {
+ out << nl << "[" << i << "] = ";
+ (*p)->printI(out, history);
+ }
+ out << eb;
+}
+
+void
+Transform::SequenceData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ SequenceDataPtr s = SequenceDataPtr::dynamicCast(data);
+ if(s && isCompatible(_type, s->_type))
+ {
+ DataList elements;
+ for(DataList::const_iterator p = s->_elements.begin(); p != s->_elements.end(); ++p)
+ {
+ DataPtr element = _factory->create(_type->type(), _readOnly);
+ //
+ // We add the element regardless of whether transform() succeeds in order to
+ // preserve the original sequence size and order.
+ //
+ element->transform((*p), interceptor);
+ elements.push_back(element);
+ }
+ _elements = elements;
+ _length = _factory->createInteger(static_cast<Ice::Long>(_elements.size()), true);
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+//
+// EnumData
+//
+Transform::EnumData::EnumData(const Slice::EnumPtr& type, const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _type(type), _value(0)
+{
+ _count = static_cast<long>(type->getEnumerators().size());
+}
+
+Transform::EnumData::EnumData(const Slice::EnumPtr& type, const ErrorReporterPtr& errorReporter, bool readOnly,
+ Ice::Int value) :
+ Data(errorReporter, readOnly), _type(type), _value(value)
+{
+ _count = static_cast<long>(type->getEnumerators().size());
+}
+
+Transform::DataPtr
+Transform::EnumData::getMember(const string&) const
+{
+ return 0;
+}
+
+Transform::DataPtr
+Transform::EnumData::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of enum value");
+ return 0;
+}
+
+bool
+Transform::EnumData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::EnumData::operator!=(const Data& rhs) const
+{
+ const EnumData* e = dynamic_cast<const EnumData*>(&rhs);
+ if(!e || _type->scoped() != e->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value != e->_value;
+}
+
+bool
+Transform::EnumData::operator<(const Data& rhs) const
+{
+ const EnumData* e = dynamic_cast<const EnumData*>(&rhs);
+ if(!e || _type->scoped() != e->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _value < e->_value;
+}
+
+void
+Transform::EnumData::registerObjects(ObjectDataMap& map) const
+{
+}
+
+void
+Transform::EnumData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::EnumData::set(const DataPtr& value, DataInterceptor& interceptor, bool convert)
+{
+ IntegerDataPtr i = IntegerDataPtr::dynamicCast(value);
+ if(i && convert)
+ {
+ Ice::Long v = i->integerValue();
+ if(v < 0 || v > _count)
+ {
+ _errorReporter->rangeError(i->toString(), _type);
+ }
+ else
+ {
+ _value = v;
+ _name.clear();
+ }
+ }
+ else if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::EnumData::clone() const
+{
+ return new EnumData(_type, _errorReporter, _value);
+}
+
+Slice::TypePtr
+Transform::EnumData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::EnumData::destroy()
+{
+}
+
+void
+Transform::EnumData::marshal(IceInternal::BasicStream& os) const
+{
+ if(_count <= 127)
+ {
+ os.write(static_cast<Ice::Byte>(_value));
+ }
+ else if(_count <= 32767)
+ {
+ os.write(static_cast<Ice::Short>(_value));
+ }
+ else
+ {
+ os.write(_value);
+ }
+}
+
+void
+Transform::EnumData::unmarshal(IceInternal::BasicStream& is)
+{
+ if(_count <= 127)
+ {
+ Ice::Byte val;
+ is.read(val);
+ _value = val & 0xff;
+ }
+ else if(_count <= 32767)
+ {
+ Ice::Short val;
+ is.read(val);
+ _value = val;
+ }
+ else
+ {
+ is.read(_value);
+ }
+}
+
+bool
+Transform::EnumData::booleanValue(bool) const
+{
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::EnumData::integerValue(bool convert) const
+{
+ if(convert)
+ {
+ return _value;
+ }
+ else
+ {
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+ }
+}
+
+double
+Transform::EnumData::doubleValue(bool) const
+{
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::EnumData::stringValue(bool) const
+{
+ _errorReporter->error("enum " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::EnumData::toString() const
+{
+ if(_name.empty())
+ {
+ Slice::EnumeratorList l = _type->getEnumerators();
+ Slice::EnumeratorList::const_iterator p = l.begin();
+ Ice::Int i = _value;
+ while(i > 0)
+ {
+ ++p;
+ assert(p != l.end());
+ --i;
+ }
+ const_cast<string&>(_name) = (*p)->name();
+ }
+ return _name;
+}
+
+Ice::Int
+Transform::EnumData::getValue() const
+{
+ return _value;
+}
+
+bool
+Transform::EnumData::setValue(Ice::Int v)
+{
+ if(v >= 0 && v < _count)
+ {
+ _value = v;
+ _name.clear();
+ return true;
+ }
+ return false;
+}
+
+bool
+Transform::EnumData::setValueAsString(const string& v)
+{
+ Slice::EnumeratorList l = _type->getEnumerators();
+ Slice::EnumeratorList::const_iterator p;
+ Ice::Int i = 0;
+ for(p = l.begin(); p != l.end(); ++p, ++i)
+ {
+ if((*p)->name() == v)
+ {
+ _value = i;
+ _name = v;
+ break;
+ }
+ }
+ return p != l.end();
+}
+
+void
+Transform::EnumData::printI(IceUtil::Output& out, ObjectDataHistory&) const
+{
+ out << typeName(_type) << "(" << toString() << ")";
+}
+
+void
+Transform::EnumData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ EnumDataPtr e = EnumDataPtr::dynamicCast(data);
+ StringDataPtr s = StringDataPtr::dynamicCast(data);
+ if(e && _type->scoped() == e->_type->scoped())
+ {
+ //
+ // Get the enumerator's name and attempt to find it in our type.
+ //
+ string name = e->toString();
+ if(!setValueAsString(name))
+ {
+ _errorReporter->conversionError(name, _type);
+ }
+ }
+ else if(s)
+ {
+ string v = s->stringValue();
+ if(!setValueAsString(v))
+ {
+ _errorReporter->conversionError(v, _type);
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+//
+// DictionaryData
+//
+Transform::DictionaryData::DictionaryData(const DataFactoryPtr& factory, const Slice::DictionaryPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ _length = _factory->createInteger(0, true);
+}
+
+Transform::DictionaryData::DictionaryData(const DataFactoryPtr& factory, const Slice::DictionaryPtr& type,
+ const ErrorReporterPtr& errorReporter, bool readOnly, const DataMap& map) :
+ Data(errorReporter, readOnly), _factory(factory), _type(type)
+{
+ for(DataMap::const_iterator p = map.begin(); p != map.end(); ++p)
+ {
+ _map.insert(DataMap::value_type(p->first->clone(), p->second->clone()));
+ }
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+}
+
+Transform::DataPtr
+Transform::DictionaryData::getMember(const string& member) const
+{
+ if(member == "length")
+ {
+ return _length;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::DictionaryData::getElement(const DataPtr& element) const
+{
+ // TODO: Validate element's type
+
+ DataMap::const_iterator p = _map.find(element);
+ if(p != _map.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+bool
+Transform::DictionaryData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::DictionaryData::operator!=(const Data& rhs) const
+{
+ const DictionaryData* d = dynamic_cast<const DictionaryData*>(&rhs);
+ if(!d || _type->scoped() != d->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _map != d->_map;
+}
+
+bool
+Transform::DictionaryData::operator<(const Data& rhs) const
+{
+ const DictionaryData* d = dynamic_cast<const DictionaryData*>(&rhs);
+ if(!d || _type->scoped() != d->_type->scoped())
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ assert(false);
+ }
+
+ return _map < d->_map;
+}
+
+void
+Transform::DictionaryData::registerObjects(ObjectDataMap& map) const
+{
+ if(_type->valueType()->usesClasses())
+ {
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ p->second->registerObjects(map);
+ }
+ }
+}
+
+void
+Transform::DictionaryData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::DictionaryData::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ if(value->getType()->unit().get() != _type->unit().get())
+ {
+ transform(value, interceptor);
+ }
+ else
+ {
+ transformI(value, interceptor);
+ }
+}
+
+Transform::DataPtr
+Transform::DictionaryData::clone() const
+{
+ return new DictionaryData(_factory, _type, _errorReporter, _readOnly, _map);
+}
+
+Slice::TypePtr
+Transform::DictionaryData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::DictionaryData::destroy()
+{
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ p->first->destroy();
+ p->second->destroy();
+ }
+}
+
+void
+Transform::DictionaryData::marshal(IceInternal::BasicStream& os) const
+{
+ os.writeSize(_map.size());
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ p->first->marshal(os);
+ p->second->marshal(os);
+ }
+}
+
+void
+Transform::DictionaryData::unmarshal(IceInternal::BasicStream& is)
+{
+ Slice::TypePtr keyType = _type->keyType();
+ Slice::TypePtr valueType = _type->valueType();
+
+ Ice::Int sz;
+ is.readSize(sz);
+
+ for(Ice::Int i = 0; i < sz; ++i)
+ {
+ DataPtr key = _factory->create(keyType, _readOnly);
+ key->unmarshal(is);
+
+ DataPtr value = _factory->create(valueType, _readOnly);
+ value->unmarshal(is);
+
+ _map.insert(DataMap::value_type(key, value));
+ }
+
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+}
+
+bool
+Transform::DictionaryData::booleanValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::DictionaryData::integerValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::DictionaryData::doubleValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::DictionaryData::stringValue(bool) const
+{
+ _errorReporter->error("dictionary " + typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::DictionaryData::toString() const
+{
+ return stringValue();
+}
+
+void
+Transform::DictionaryData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "dictionary " << typeName(_type) << " (size = " << _map.size() << ")";
+ out << sb;
+ for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p)
+ {
+ out << nl;
+ p->first->printI(out, history);
+ out << " => ";
+ p->second->printI(out, history);
+ }
+ out << eb;
+}
+
+void
+Transform::DictionaryData::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ DictionaryDataPtr d = DictionaryDataPtr::dynamicCast(data);
+ if(d && isCompatible(_type, d->_type))
+ {
+ DataMap map;
+ for(DataMap::const_iterator p = d->_map.begin(); p != d->_map.end(); ++p)
+ {
+ DataPtr key = _factory->create(_type->keyType(), _readOnly);
+ DataPtr value = _factory->create(_type->valueType(), _readOnly);
+ key->transform(p->first, interceptor);
+ value->transform(p->second, interceptor);
+ DataMap::const_iterator q = map.find(key);
+ if(q != map.end())
+ {
+ ostringstream ostr;
+ ostr << "duplicate dictionary key (";
+ key->print(ostr);
+ ostr << ")";
+ _errorReporter->warning(ostr.str());
+ }
+ else
+ {
+ map.insert(DataMap::value_type(key, value));
+ }
+ }
+ _map = map;
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+Transform::DataMap
+Transform::DictionaryData::getElements() const
+{
+ return _map;
+}
+
+void
+Transform::DictionaryData::put(const DataPtr& key, const DataPtr& value, DataInterceptor& interceptor, bool convert)
+{
+ assert(!readOnly());
+
+ if(!isCompatible(_type->keyType(), key->getType()))
+ {
+ _errorReporter->typeMismatchError(_type->keyType(), key->getType(), true);
+ }
+ if(!isCompatible(_type->valueType(), value->getType()))
+ {
+ _errorReporter->typeMismatchError(_type->valueType(), value->getType(), true);
+ }
+
+ DataPtr newKey = _factory->create(_type->keyType(), false);
+ newKey->set(key, interceptor, convert);
+ DataPtr newValue = _factory->create(_type->valueType(), false);
+ newValue->set(value, interceptor, convert);
+
+ DataMap::iterator p = _map.find(newKey);
+ if(p != _map.end())
+ {
+ p->first->destroy();
+ p->second->destroy();
+ }
+
+ _map.insert(DataMap::value_type(newKey, newValue));
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+}
+
+void
+Transform::DictionaryData::remove(const DataPtr& key)
+{
+ DataMap::iterator p = _map.find(key);
+ if(p != _map.end())
+ {
+ p->first->destroy();
+ p->second->destroy();
+ _map.erase(p);
+ _length = _factory->createInteger(static_cast<Ice::Long>(_map.size()), true);
+ }
+}
+
+//
+// ObjectData
+//
+Transform::ObjectData::ObjectData(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly) :
+ Data(factory->getErrorReporter(), readOnly), _type(type), _refCount(0)
+{
+ //
+ // Create a Data object for the facet map. We add this to the _members map so that
+ // the `ice_facets' member is handled like all other members.
+ //
+ Slice::TypeList l = _type->unit()->lookupType("::_FacetMap", false);
+ assert(!l.empty());
+ _facetMap = factory->create(l.front(), readOnly);
+ _members["ice_facets"] = _facetMap;
+
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(type);
+ if(decl)
+ {
+ Slice::ClassDefPtr def = decl->definition();
+ assert(def);
+ Slice::DataMemberList members = def->allDataMembers();
+ for(Slice::DataMemberList::iterator p = members.begin(); p != members.end(); ++p)
+ {
+ _members[(*p)->name()] = factory->create((*p)->type(), _readOnly);
+ }
+ _id = factory->createString(decl->scoped(), true);
+ }
+ else
+ {
+ _id = factory->createString("::Ice::Object", true);
+ }
+}
+
+Transform::DataPtr
+Transform::ObjectData::getMember(const string& member) const
+{
+ if(member == "ice_id")
+ {
+ return _id;
+ }
+
+ DataMemberMap::const_iterator p = _members.find(member);
+ if(p != _members.end())
+ {
+ return p->second;
+ }
+
+ return 0;
+}
+
+Transform::DataPtr
+Transform::ObjectData::getElement(const DataPtr& element) const
+{
+ _errorReporter->error("element requested of object value");
+ return 0;
+}
+
+bool
+Transform::ObjectData::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::ObjectData::operator!=(const Data& rhs) const
+{
+ _errorReporter->error("object comparison not supported");
+ return false;
+}
+
+bool
+Transform::ObjectData::operator<(const Data& rhs) const
+{
+ _errorReporter->error("object comparison not supported");
+ return false;
+}
+
+void
+Transform::ObjectData::registerObjects(ObjectDataMap& map) const
+{
+ ObjectDataMap::iterator p = map.find(this);
+ if(p == map.end())
+ {
+ map.insert(ObjectDataMap::value_type(this, 0));
+ for(DataMemberMap::const_iterator q = _members.begin(); q != _members.end(); ++q)
+ {
+ q->second->registerObjects(map);
+ }
+ }
+}
+
+void
+Transform::ObjectData::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ ObjectDataPtr o = ObjectDataPtr::dynamicCast(data);
+ if(o)
+ {
+ assert(isCompatible(_type, o->_type));
+
+ //
+ // The source object must be present in the object map (we currently don't support
+ // transforming two ObjectData instances from the same Slice unit - this transform
+ // would be handled by-reference at the ObjectRef level). We must update the object
+ // map before transforming members in order to handle cycles.
+ //
+ ObjectDataMap& objectMap = interceptor.getObjectMap();
+ ObjectDataMap::iterator p = objectMap.find(o.get());
+ assert(p != objectMap.end());
+ assert(p->second == 0);
+ objectMap.erase(p);
+ objectMap.insert(ObjectDataMap::value_type(o.get(), this));
+
+ try
+ {
+ //
+ // Invoke transform() on members with the same name.
+ //
+ for(DataMemberMap::iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ DataMemberMap::iterator q = o->_members.find(p->first);
+ if(q != o->_members.end())
+ {
+ p->second->transform(q->second, interceptor);
+ }
+ }
+ }
+ catch(...)
+ {
+ objectMap.insert(ObjectDataMap::value_type(o.get(), 0));
+ throw;
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+}
+
+void
+Transform::ObjectData::set(const DataPtr&, DataInterceptor&, bool)
+{
+ assert(false);
+}
+
+Transform::DataPtr
+Transform::ObjectData::clone() const
+{
+ assert(false);
+ return 0;
+}
+
+Slice::TypePtr
+Transform::ObjectData::getType() const
+{
+ return _type;
+}
+
+void
+Transform::ObjectData::destroy()
+{
+ assert(false);
+}
+
+void
+Transform::ObjectData::marshal(IceInternal::BasicStream& os) const
+{
+ if(!_marshaler)
+ {
+ const_cast<Ice::ObjectPtr&>(_marshaler) = new ObjectWriter(const_cast<ObjectData*>(this));
+ }
+ os.write(_marshaler);
+}
+
+void
+Transform::ObjectData::unmarshal(IceInternal::BasicStream& is)
+{
+ //
+ // Unmarshaling is done by ObjectReader.
+ //
+ assert(false);
+}
+
+bool
+Transform::ObjectData::booleanValue(bool) const
+{
+ assert(false);
+ return 0;
+}
+
+Ice::Long
+Transform::ObjectData::integerValue(bool) const
+{
+ assert(false);
+ return 0;
+}
+
+double
+Transform::ObjectData::doubleValue(bool) const
+{
+ assert(false);
+ return 0;
+}
+
+string
+Transform::ObjectData::stringValue(bool) const
+{
+ assert(false);
+ return string();
+}
+
+string
+Transform::ObjectData::toString() const
+{
+ assert(false);
+ return string();
+}
+
+void
+Transform::ObjectData::incRef()
+{
+ _refCount++;
+}
+
+void
+Transform::ObjectData::decRef()
+{
+ assert(_refCount > 0);
+ _refCount--;
+ if(_refCount == 0)
+ {
+ destroyI();
+ }
+}
+
+void
+Transform::ObjectData::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ out << "class " << typeName(_type);
+ ObjectDataHistory::iterator p = history.find(this);
+ if(p != history.end())
+ {
+ out << " (cycle)";
+ }
+ else
+ {
+ history.insert(ObjectDataHistory::value_type(this, true));
+ out << sb;
+ for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p)
+ {
+ out << nl << p->first << " = ";
+ p->second->printI(out, history);
+ }
+ out << eb;
+ }
+}
+
+void
+Transform::ObjectData::destroyI()
+{
+ DataMemberMap members = _members;
+
+ _members.clear();
+ _marshaler = 0;
+
+ for(DataMemberMap::const_iterator p = members.begin(); p != members.end(); ++p)
+ {
+ p->second->destroy();
+ }
+}
+
+//
+// ObjectRef
+//
+Transform::ObjectRef::ObjectRef(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly) :
+ Data(factory->getErrorReporter(), readOnly), _factory(factory), _type(type)
+{
+}
+
+Transform::ObjectRef::ObjectRef(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly,
+ const ObjectDataPtr& value) :
+ Data(factory->getErrorReporter(), readOnly), _factory(factory), _type(type), _value(value)
+{
+ _value->incRef();
+}
+
+Transform::DataPtr
+Transform::ObjectRef::getMember(const string& member) const
+{
+ if(!_value)
+ {
+ _errorReporter->error("member `" + member + "' requested of nil object");
+ }
+
+ return _value->getMember(member);
+}
+
+Transform::DataPtr
+Transform::ObjectRef::getElement(const DataPtr&) const
+{
+ _errorReporter->error("element requested of object value");
+ return 0;
+}
+
+bool
+Transform::ObjectRef::operator==(const Data& rhs) const
+{
+ return !operator!=(rhs);
+}
+
+bool
+Transform::ObjectRef::operator!=(const Data& rhs) const
+{
+ const ObjectRef* r = dynamic_cast<const ObjectRef*>(&rhs);
+ if(!r)
+ {
+ _errorReporter->typeMismatchError(_type, rhs.getType(), true);
+ }
+
+ if(!_value || !r->_value)
+ {
+ return !_value && r->_value;
+ }
+
+ //
+ // Reference comparison.
+ //
+ return _value.get() != r->_value.get();
+}
+
+bool
+Transform::ObjectRef::operator<(const Data& rhs) const
+{
+ _errorReporter->error("object comparison not supported");
+ return false;
+}
+
+void
+Transform::ObjectRef::registerObjects(ObjectDataMap& map) const
+{
+ if(_value)
+ {
+ _value->registerObjects(map);
+ }
+}
+
+void
+Transform::ObjectRef::transform(const DataPtr& data, DataInterceptor& interceptor)
+{
+ if(interceptor.preTransform(this, data))
+ {
+ transformI(data, interceptor);
+ }
+ interceptor.postTransform(this, data);
+}
+
+void
+Transform::ObjectRef::set(const DataPtr& value, DataInterceptor& interceptor, bool)
+{
+ transformI(value, interceptor);
+}
+
+Transform::DataPtr
+Transform::ObjectRef::clone() const
+{
+ return new ObjectRef(_factory, _type, _value);
+}
+
+Slice::TypePtr
+Transform::ObjectRef::getType() const
+{
+ return _type;
+}
+
+void
+Transform::ObjectRef::destroy()
+{
+ if(_value)
+ {
+ _value->decRef();
+ _value = 0;
+ }
+}
+
+void
+Transform::ObjectRef::marshal(IceInternal::BasicStream& os) const
+{
+ if(!_value)
+ {
+ os.write(Ice::ObjectPtr());
+ return;
+ }
+
+ _value->marshal(os);
+}
+
+static void
+patchObject(void* addr, Ice::ObjectPtr& v)
+{
+ if(v)
+ {
+ Transform::ObjectRef* ref = static_cast<Transform::ObjectRef*>(addr);
+ assert(ref);
+
+ Transform::ObjectReaderPtr reader = Transform::ObjectReaderPtr::dynamicCast(v);
+ assert(reader);
+
+ ref->setValue(reader->getValue());
+ }
+}
+
+void
+Transform::ObjectRef::unmarshal(IceInternal::BasicStream& is)
+{
+ is.read(patchObject, this);
+}
+
+bool
+Transform::ObjectRef::booleanValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to boolean");
+ return 0;
+}
+
+Ice::Long
+Transform::ObjectRef::integerValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to integer");
+ return 0;
+}
+
+double
+Transform::ObjectRef::doubleValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to double");
+ return 0;
+}
+
+string
+Transform::ObjectRef::stringValue(bool) const
+{
+ _errorReporter->error(typeName(_type) + " cannot be converted to string");
+ return string();
+}
+
+string
+Transform::ObjectRef::toString() const
+{
+ return stringValue();
+}
+
+void
+Transform::ObjectRef::instantiate()
+{
+ ObjectDataPtr data = new ObjectData(_factory, _type, _readOnly);
+ setValue(data);
+}
+
+void
+Transform::ObjectRef::setValue(const ObjectDataPtr& value)
+{
+ // TODO: Type check?
+ ObjectDataPtr oldValue = _value;
+ _value = value;
+ if(_value)
+ {
+ _value->incRef();
+ }
+ if(oldValue)
+ {
+ oldValue->decRef();
+ }
+}
+
+void
+Transform::ObjectRef::printI(IceUtil::Output& out, ObjectDataHistory& history) const
+{
+ if(!_value)
+ {
+ out << typeName(_type) << "(nil)";
+ }
+ else
+ {
+ ostringstream ostr;
+ _value->printI(out, history);
+ }
+}
+
+void
+Transform::ObjectRef::transformI(const DataPtr& data, DataInterceptor& interceptor)
+{
+ ObjectRefPtr o = ObjectRefPtr::dynamicCast(data);
+ if(!o)
+ {
+ _errorReporter->typeMismatchError(_type, data->getType(), false);
+ }
+
+ if(!o->_value)
+ {
+ //
+ // Allow a nil value from type Object.
+ //
+ if(Slice::BuiltinPtr::dynamicCast(o->_type) || isCompatible(_type, o->_type))
+ {
+ setValue(0);
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, o->_type, false);
+ }
+ }
+ else
+ {
+ Slice::TypePtr otype = o->_value->getType();
+ if(isCompatible(_type, otype))
+ {
+ //
+ // If the types are in the same Slice unit, then we can simply
+ // copy the reference. Otherwise, we check the object map to
+ // see if an equivalent object has already been created, and
+ // if not, then we have to create one.
+ //
+ if(_type->unit().get() == otype->unit().get())
+ {
+ setValue(o->_value);
+ }
+ else
+ {
+ ObjectDataMap& objectMap = interceptor.getObjectMap();
+ ObjectDataMap::iterator p = objectMap.find(o->_value.get());
+ if(p != objectMap.end() && p->second)
+ {
+ setValue(p->second);
+ }
+ else
+ {
+ string name = typeName(otype);
+ Slice::TypeList l = _type->unit()->lookupType(name, false);
+ if(l.empty())
+ {
+ // TODO: Slice object? Or missing type exception?
+ _errorReporter->warning("type `" + name + "' not found");
+ }
+ else
+ {
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(l.front());
+ if(decl)
+ {
+ Slice::ClassDefPtr def = decl->definition();
+ if(!def)
+ {
+ _errorReporter->error("no definition for " + name);
+ }
+ }
+ ObjectDataPtr data = new ObjectData(_factory, l.front(), _readOnly);
+ data->transform(o->_value, interceptor);
+ setValue(data);
+ }
+ }
+ }
+ }
+ else
+ {
+ _errorReporter->typeMismatchError(_type, otype, false);
+ }
+ }
+}
+
+//
+// ObjectFactory
+//
+Transform::ObjectFactory::ObjectFactory(const DataFactoryPtr& factory, const Slice::UnitPtr& unit) :
+ _factory(factory), _unit(unit)
+{
+}
+
+Ice::ObjectPtr
+Transform::ObjectFactory::create(const string& id)
+{
+ Ice::ObjectPtr result;
+
+ if(id == Ice::Object::ice_staticId())
+ {
+ result = new ObjectReader(_factory, _unit->builtin(Slice::Builtin::KindObject));
+ }
+ else
+ {
+ Slice::TypeList l = _unit->lookupTypeNoBuiltin(id);
+ if(!l.empty())
+ {
+ Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(l.front());
+ if(!decl)
+ {
+ _factory->getErrorReporter()->error("Slice definition for `" + id + "' is not a class");
+ }
+ Slice::ClassDefPtr def = decl->definition();
+ if(!def)
+ {
+ _factory->getErrorReporter()->error("no class definition for `" + id + "'");
+ }
+ result = new ObjectReader(_factory, decl);
+ }
+ }
+
+ return result;
+}
+
+void
+Transform::ObjectFactory::destroy()
+{
+}
diff --git a/cpp/src/Transform/Data.h b/cpp/src/Transform/Data.h
new file mode 100644
index 00000000000..92c2268cb2d
--- /dev/null
+++ b/cpp/src/Transform/Data.h
@@ -0,0 +1,658 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_DATA_H
+#define TRANSFORM_DATA_H
+
+#include <Ice/Ice.h>
+#include <Slice/Parser.h>
+#include <IceUtil/OutputUtil.h>
+#include <Transform/Error.h>
+
+namespace Transform
+{
+
+class DataFactory;
+typedef IceUtil::Handle<DataFactory> DataFactoryPtr;
+
+class Data;
+typedef IceUtil::Handle<Data> DataPtr;
+
+typedef std::map<std::string, DataPtr> DataMemberMap;
+typedef std::vector<DataPtr> DataList;
+typedef std::map<DataPtr, DataPtr> DataMap;
+
+class ObjectWriter;
+class ObjectReader;
+
+class ObjectData;
+typedef IceUtil::Handle<ObjectData> ObjectDataPtr;
+typedef std::map<const ObjectData*, ObjectDataPtr> ObjectDataMap;
+typedef std::map<const ObjectData*, bool> ObjectDataHistory;
+
+class DataInterceptor
+{
+public:
+
+ virtual ~DataInterceptor();
+
+ virtual bool preTransform(const DataPtr&, const DataPtr&) = 0;
+ virtual void postTransform(const DataPtr&, const DataPtr&) = 0;
+ virtual ObjectDataMap& getObjectMap() = 0;
+};
+
+class DataInitializer : virtual public IceUtil::SimpleShared
+{
+public:
+
+ virtual ~DataInitializer();
+
+ virtual void initialize(const DataFactoryPtr&, const DataPtr&, const Ice::CommunicatorPtr&) = 0;
+};
+typedef IceUtil::Handle<DataInitializer> DataInitializerPtr;
+
+class DataFactory : public IceUtil::SimpleShared
+{
+public:
+
+ DataFactory(const Ice::CommunicatorPtr&, const Slice::UnitPtr&, const ErrorReporterPtr&);
+
+ DataPtr create(const Slice::TypePtr&, bool);
+ DataPtr createBoolean(bool, bool);
+ DataPtr createInteger(Ice::Long, bool);
+ DataPtr createDouble(double, bool);
+ DataPtr createString(const std::string&, bool);
+ DataPtr createNil(bool);
+
+ Slice::BuiltinPtr getBuiltin(Slice::Builtin::Kind) const;
+
+ void addInitializer(const std::string&, const DataInitializerPtr&);
+ void enableInitializers();
+ void disableInitializers();
+ ErrorReporterPtr getErrorReporter() const;
+
+private:
+
+ DataPtr createImpl(const Slice::TypePtr&, bool);
+
+ Ice::CommunicatorPtr _communicator;
+ Slice::UnitPtr _unit; // Only used for creating builtin types.
+ ErrorReporterPtr _errorReporter;
+ typedef std::map<std::string, DataInitializerPtr> InitMap;
+ InitMap _initializers;
+ bool _initializersEnabled;
+};
+
+class Data : public IceUtil::SimpleShared
+{
+public:
+
+ virtual ~Data();
+
+ virtual DataPtr getMember(const std::string&) const = 0;
+ virtual DataPtr getElement(const DataPtr&) const = 0;
+
+ virtual bool operator==(const Data&) const = 0;
+ virtual bool operator!=(const Data&) const = 0;
+ virtual bool operator<(const Data&) const = 0;
+
+ virtual void registerObjects(ObjectDataMap&) const = 0;
+ virtual void transform(const DataPtr&, DataInterceptor&) = 0;
+ virtual void set(const DataPtr&, DataInterceptor&, bool) = 0;
+ virtual DataPtr clone() const = 0;
+
+ bool readOnly() const;
+ virtual Slice::TypePtr getType() const = 0;
+ void print(std::ostream&) const;
+ virtual void destroy() = 0;
+
+ virtual void marshal(IceInternal::BasicStream&) const = 0;
+ virtual void unmarshal(IceInternal::BasicStream&) = 0;
+
+ virtual bool booleanValue(bool = false) const = 0;
+ virtual Ice::Long integerValue(bool = false) const = 0;
+ virtual double doubleValue(bool = false) const = 0;
+ virtual std::string stringValue(bool = false) const = 0;
+ virtual std::string toString() const = 0;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const = 0;
+
+protected:
+
+ Data(const ErrorReporterPtr&, bool);
+
+ bool isCompatible(const Slice::TypePtr&, const Slice::TypePtr&);
+ bool checkClasses(const Slice::ClassDeclPtr&, const Slice::ClassDeclPtr&);
+
+ ErrorReporterPtr _errorReporter;
+ bool _readOnly;
+};
+
+class PrimitiveData : public Data
+{
+public:
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void destroy();
+
+protected:
+
+ PrimitiveData(const ErrorReporterPtr&, bool);
+};
+typedef IceUtil::Handle<PrimitiveData> PrimitiveDataPtr;
+
+class BooleanData : public PrimitiveData
+{
+public:
+
+ BooleanData(const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool);
+ BooleanData(const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool, bool);
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ Slice::BuiltinPtr _type;
+ bool _value;
+};
+typedef IceUtil::Handle<BooleanData> BooleanDataPtr;
+
+class IntegerData : public PrimitiveData
+{
+public:
+
+ IntegerData(const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool);
+ IntegerData(const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool, Ice::Long);
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ bool rangeCheck(Ice::Long) const;
+ static std::string toString(Ice::Long);
+
+ Slice::BuiltinPtr _type;
+ Ice::Long _value;
+};
+typedef IceUtil::Handle<IntegerData> IntegerDataPtr;
+
+class DoubleData : public PrimitiveData
+{
+public:
+
+ DoubleData(const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool);
+ DoubleData(const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool, double);
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ Slice::BuiltinPtr _type;
+ double _value;
+};
+typedef IceUtil::Handle<DoubleData> DoubleDataPtr;
+
+class StringData : public PrimitiveData
+{
+public:
+
+ StringData(const DataFactoryPtr&, const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool);
+ StringData(const DataFactoryPtr&, const Slice::BuiltinPtr&, const ErrorReporterPtr&, bool, const std::string&);
+
+ virtual DataPtr getMember(const std::string&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ void setValue(const std::string&);
+
+ DataFactoryPtr _factory;
+ Slice::BuiltinPtr _type;
+ std::string _value;
+ DataPtr _length;
+};
+typedef IceUtil::Handle<StringData> StringDataPtr;
+
+class ProxyData : public Data
+{
+public:
+
+ ProxyData(const Slice::TypePtr&, const Ice::CommunicatorPtr&, const ErrorReporterPtr&, bool);
+ ProxyData(const Slice::TypePtr&, const Ice::CommunicatorPtr&, const ErrorReporterPtr&, bool, const Ice::ObjectPrx&);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+ virtual void destroy();
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ Ice::ObjectPrx getValue() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ void transformI(const DataPtr&);
+ void setValue(const std::string&);
+
+ Slice::TypePtr _type; // Can be Builtin or Proxy
+ Ice::CommunicatorPtr _communicator;
+ Ice::ObjectPrx _value;
+ std::string _str;
+};
+typedef IceUtil::Handle<ProxyData> ProxyDataPtr;
+
+class StructData : public Data
+{
+public:
+
+ StructData(const DataFactoryPtr&, const Slice::StructPtr&, const ErrorReporterPtr&, bool);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual void destroy();
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ DataMemberMap getMembers() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ StructData(const Slice::StructPtr&, const ErrorReporterPtr&, bool, const DataMemberMap&);
+
+ void transformI(const DataPtr&, DataInterceptor&);
+
+ Slice::StructPtr _type;
+ DataMemberMap _members;
+};
+typedef IceUtil::Handle<StructData> StructDataPtr;
+
+class SequenceData : public Data
+{
+public:
+
+ SequenceData(const DataFactoryPtr&, const Slice::SequencePtr&, const ErrorReporterPtr&, bool);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+ virtual void destroy();
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ DataList getElements() const;
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ SequenceData(const DataFactoryPtr&, const Slice::SequencePtr&, const ErrorReporterPtr&, bool, const DataList&);
+
+ void transformI(const DataPtr&, DataInterceptor&);
+
+ DataFactoryPtr _factory;
+ Slice::SequencePtr _type;
+ DataList _elements;
+ DataPtr _length;
+};
+typedef IceUtil::Handle<SequenceData> SequenceDataPtr;
+
+class EnumData : public Data
+{
+public:
+
+ EnumData(const Slice::EnumPtr&, const ErrorReporterPtr&, bool);
+ EnumData(const Slice::EnumPtr&, const ErrorReporterPtr&, bool, Ice::Int);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+ virtual void destroy();
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ Ice::Int getValue() const;
+
+ bool setValue(Ice::Int);
+ bool setValueAsString(const std::string&);
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ void transformI(const DataPtr&, DataInterceptor&);
+
+ Slice::EnumPtr _type;
+ Ice::Int _value;
+ std::string _name;
+ Ice::Int _count;
+};
+typedef IceUtil::Handle<EnumData> EnumDataPtr;
+
+class DictionaryData : public Data
+{
+public:
+
+ DictionaryData(const DataFactoryPtr&, const Slice::DictionaryPtr&, const ErrorReporterPtr&, bool);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+ virtual void destroy();
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ DataMap getElements() const;
+ void put(const DataPtr&, const DataPtr&, DataInterceptor&, bool);
+ void remove(const DataPtr&);
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ DictionaryData(const DataFactoryPtr&, const Slice::DictionaryPtr&, const ErrorReporterPtr&, bool, const DataMap&);
+
+ void transformI(const DataPtr&, DataInterceptor&);
+
+ DataFactoryPtr _factory;
+ Slice::DictionaryPtr _type;
+ DataMap _map;
+ DataPtr _length;
+};
+typedef IceUtil::Handle<DictionaryData> DictionaryDataPtr;
+
+class ObjectData : public Data
+{
+public:
+
+ ObjectData(const DataFactoryPtr&, const Slice::TypePtr&, bool);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+ virtual void destroy();
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ void incRef();
+ void decRef();
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ void destroyI();
+
+ Slice::TypePtr _type; // Can be Builtin (Object) or ClassDecl
+ DataPtr _facetMap;
+ DataMemberMap _members;
+ Ice::ObjectPtr _marshaler;
+ Ice::Int _refCount;
+ DataPtr _id;
+
+ friend class ObjectWriter;
+ friend class ObjectReader;
+};
+
+class ObjectRef : public Data
+{
+public:
+
+ ObjectRef(const DataFactoryPtr&, const Slice::TypePtr&, bool);
+ ObjectRef(const DataFactoryPtr&, const Slice::TypePtr&, bool, const ObjectDataPtr&);
+
+ virtual DataPtr getMember(const std::string&) const;
+ virtual DataPtr getElement(const DataPtr&) const;
+
+ virtual bool operator==(const Data&) const;
+ virtual bool operator!=(const Data&) const;
+ virtual bool operator<(const Data&) const;
+
+ virtual void registerObjects(ObjectDataMap&) const;
+ virtual void transform(const DataPtr&, DataInterceptor&);
+ virtual void set(const DataPtr&, DataInterceptor&, bool);
+ virtual DataPtr clone() const;
+
+ virtual Slice::TypePtr getType() const;
+ virtual void destroy();
+
+ virtual void marshal(IceInternal::BasicStream&) const;
+ virtual void unmarshal(IceInternal::BasicStream&);
+
+ virtual bool booleanValue(bool = false) const;
+ virtual Ice::Long integerValue(bool = false) const;
+ virtual double doubleValue(bool = false) const;
+ virtual std::string stringValue(bool = false) const;
+ virtual std::string toString() const;
+
+ void instantiate();
+ void setValue(const ObjectDataPtr&);
+
+ virtual void printI(IceUtil::Output&, ObjectDataHistory&) const;
+
+private:
+
+ void transformI(const DataPtr&, DataInterceptor&);
+
+ DataFactoryPtr _factory;
+ Slice::TypePtr _type; // Formal type: can be Builtin (Object) or ClassDecl
+ ObjectDataPtr _value;
+};
+typedef IceUtil::Handle<ObjectRef> ObjectRefPtr;
+
+class ObjectFactory : public Ice::ObjectFactory
+{
+public:
+
+ ObjectFactory(const DataFactoryPtr&, const Slice::UnitPtr&);
+
+ virtual Ice::ObjectPtr create(const std::string&);
+ virtual void destroy();
+
+private:
+
+ DataFactoryPtr _factory;
+ Slice::UnitPtr _unit;
+};
+
+} // End of namespace Transform
+
+#endif
diff --git a/cpp/src/Transform/Error.cpp b/cpp/src/Transform/Error.cpp
new file mode 100644
index 00000000000..8f4e4290ae9
--- /dev/null
+++ b/cpp/src/Transform/Error.cpp
@@ -0,0 +1,192 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Error.h>
+#include <Transform/Exception.h>
+#include <Transform/TransformUtil.h>
+
+using namespace std;
+
+//
+// ErrorReporter
+//
+Transform::ErrorReporter::ErrorReporter(ostream& out) :
+ _out(out), _raise(true)
+{
+}
+
+ostream&
+Transform::ErrorReporter::stream() const
+{
+ return _out;
+}
+
+void
+Transform::ErrorReporter::warning(const string& msg)
+{
+ if(!_descName.empty())
+ {
+ _out << "warning in <" << _descName << "> descriptor, line " << _descLine << ": " << msg << endl;
+ }
+ else
+ {
+ _out << "warning: " << msg << endl;
+ }
+}
+
+void
+Transform::ErrorReporter::error(const string& msg)
+{
+ ostringstream ostr;
+ if(!_descName.empty())
+ {
+ ostr << "error in <" << _descName << "> descriptor, line " << _descLine << ": " << msg << endl;
+ }
+ else
+ {
+ ostr << "error: " << msg << endl;
+ }
+ throw TransformException(__FILE__, __LINE__, ostr.str());
+}
+
+void
+Transform::ErrorReporter::typeMismatchError(const Slice::TypePtr& expected, const Slice::TypePtr& received, bool fatal)
+{
+ ostringstream ostr;
+ ostr << "type mismatch: expected " << typeName(expected) << " but received " << typeName(received);
+
+ if(_raise || fatal)
+ {
+ error(ostr.str());
+ }
+ else
+ {
+ warning(ostr.str());
+ }
+}
+
+void
+Transform::ErrorReporter::conversionError(const string& value, const Slice::TypePtr& type)
+{
+ ostringstream ostr;
+ ostr << "unable to convert `" << value << "' to " << typeName(type);
+
+ if(_raise)
+ {
+ error(ostr.str());
+ }
+ else
+ {
+ warning(ostr.str());
+ }
+}
+
+void
+Transform::ErrorReporter::rangeError(const string& value, const Slice::TypePtr& type)
+{
+ ostringstream ostr;
+ ostr << "value `" << value << "' is out of range for type " << typeName(type);
+
+ if(_raise)
+ {
+ error(ostr.str());
+ }
+ else
+ {
+ warning(ostr.str());
+ }
+}
+
+void
+Transform::ErrorReporter::expressionSyntaxError(const string& msg)
+{
+ assert(!_expression.empty());
+ ostringstream ostr;
+ ostr << "syntax error in expression `" << _expression << "': " << msg;
+ error(ostr.str());
+}
+
+void
+Transform::ErrorReporter::descriptorError(const string& msg, int line)
+{
+ ostringstream ostr;
+ ostr << "XML error on line " << line << ":" << endl << msg;
+ error(ostr.str());
+}
+
+void
+Transform::ErrorReporter::setDescriptor(const string& name, int line)
+{
+ _descName = name;
+ _descLine = line;
+}
+
+void
+Transform::ErrorReporter::getDescriptor(string& name, int& line)
+{
+ name = _descName;
+ line = _descLine;
+}
+
+void
+Transform::ErrorReporter::clearDescriptor()
+{
+ _descName.clear();
+}
+
+void
+Transform::ErrorReporter::setExpression(const string& expr)
+{
+ _expression = expr;
+}
+
+void
+Transform::ErrorReporter::clearExpression()
+{
+ _expression.clear();
+}
+
+bool
+Transform::ErrorReporter::raise() const
+{
+ return _raise;
+}
+
+void
+Transform::ErrorReporter::raise(bool b)
+{
+ _raise = b;
+}
+
+//
+// DescriptorErrorContext
+//
+Transform::DescriptorErrorContext::DescriptorErrorContext(const ErrorReporterPtr& errorReporter, const string& name,
+ int line) :
+ _errorReporter(errorReporter)
+{
+ //
+ // Save the existing descriptor information before changing it.
+ //
+ _errorReporter->getDescriptor(_name, _line);
+ _errorReporter->setDescriptor(name, line);
+}
+
+Transform::DescriptorErrorContext::~DescriptorErrorContext()
+{
+ //
+ // Restore the original descriptor information.
+ //
+ _errorReporter->setDescriptor(_name, _line);
+}
diff --git a/cpp/src/Transform/Error.h b/cpp/src/Transform/Error.h
new file mode 100644
index 00000000000..1908905202d
--- /dev/null
+++ b/cpp/src/Transform/Error.h
@@ -0,0 +1,75 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_ERROR_H
+#define TRANSFORM_ERROR_H
+
+#include <Slice/Parser.h>
+
+namespace Transform
+{
+
+class ErrorReporter : public IceUtil::SimpleShared
+{
+public:
+
+ ErrorReporter(std::ostream&);
+
+ std::ostream& stream() const;
+
+ void warning(const std::string&);
+ void error(const std::string&);
+ void typeMismatchError(const Slice::TypePtr&, const Slice::TypePtr&, bool);
+ void conversionError(const std::string&, const Slice::TypePtr&);
+ void rangeError(const std::string&, const Slice::TypePtr&);
+ void expressionSyntaxError(const std::string&);
+ void descriptorError(const std::string&, int);
+
+ void setDescriptor(const std::string&, int);
+ void getDescriptor(std::string&, int&);
+ void clearDescriptor();
+
+ void setExpression(const std::string&);
+ void clearExpression();
+
+ bool raise() const;
+ void raise(bool);
+
+private:
+
+ std::ostream& _out;
+ std::string _descName;
+ int _descLine;
+ std::string _expression;
+ bool _raise;
+};
+typedef IceUtil::Handle<ErrorReporter> ErrorReporterPtr;
+
+class DescriptorErrorContext
+{
+public:
+
+ DescriptorErrorContext(const ErrorReporterPtr&, const std::string&, int);
+ ~DescriptorErrorContext();
+
+private:
+
+ ErrorReporterPtr _errorReporter;
+ std::string _name;
+ int _line;
+};
+
+} // End of namespace Transform
+
+#endif
diff --git a/cpp/src/Transform/Exception.cpp b/cpp/src/Transform/Exception.cpp
new file mode 100644
index 00000000000..dc25832fa9c
--- /dev/null
+++ b/cpp/src/Transform/Exception.cpp
@@ -0,0 +1,60 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Exception.h>
+
+using namespace std;
+
+//
+// TransformException
+//
+Transform::TransformException::TransformException(const char* file, int line, const string& reason) :
+ IceUtil::Exception(file, line), _reason(reason)
+{
+}
+
+string
+Transform::TransformException::ice_name() const
+{
+ return "Transform::TransformException";
+}
+
+void
+Transform::TransformException::ice_print(ostream& out) const
+{
+ IceUtil::Exception::ice_print(out);
+ out << ":\nerror occurred during transformation";
+ if(!_reason.empty())
+ {
+ out << ":\n" << _reason;
+ }
+}
+
+IceUtil::Exception*
+Transform::TransformException::ice_clone() const
+{
+ return new TransformException(ice_file(), ice_line(), _reason);
+}
+
+void
+Transform::TransformException::ice_throw() const
+{
+ throw *this;
+}
+
+string
+Transform::TransformException::reason() const
+{
+ return _reason;
+}
diff --git a/cpp/src/Transform/Grammar.y b/cpp/src/Transform/Grammar.y
new file mode 100644
index 00000000000..089d5078f84
--- /dev/null
+++ b/cpp/src/Transform/Grammar.y
@@ -0,0 +1,264 @@
+%{
+
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/GrammarUtil.h>
+
+#ifdef _WIN32
+// I get these warnings from some bison versions:
+// warning C4102: 'yyoverflowlab' : unreferenced label
+# pragma warning( disable : 4102 )
+// warning C4065: switch statement contains 'default' but no 'case' labels
+# pragma warning( disable : 4065 )
+#endif
+
+using namespace std;
+using namespace Transform;
+
+void
+transform_error(const char* s)
+{
+ // yacc and recent versions of Bison use "syntax error" instead
+ // of "parse error".
+
+ if(strcmp(s, "parse error") == 0)
+ {
+ parseErrorReporter->expressionSyntaxError("syntax error");
+ }
+ else
+ {
+ parseErrorReporter->expressionSyntaxError(s);
+ }
+}
+
+%}
+
+%pure_parser
+%name_prefix="transform_"
+
+%token TOK_AND
+%token TOK_OR
+%token TOK_NOT
+%token TOK_ADD
+%token TOK_SUB
+%token TOK_MUL
+%token TOK_DIV
+%token TOK_MOD
+%token TOK_LPAREN
+%token TOK_RPAREN
+%token TOK_LBRACKET
+%token TOK_RBRACKET
+%token TOK_LESS_THAN
+%token TOK_GREATER_THAN
+%token TOK_LESS_EQUAL
+%token TOK_GREATER_EQUAL
+%token TOK_EQUAL
+%token TOK_TRUE
+%token TOK_FALSE
+%token TOK_NIL
+%token TOK_SCOPE_DELIMITER
+%token TOK_IDENTIFIER
+%token TOK_STRING_LITERAL
+%token TOK_INTEGER_LITERAL
+%token TOK_FLOATING_POINT_LITERAL
+
+%left TOK_OR
+%left TOK_AND
+%nonassoc TOK_LESS_THAN TOK_GREATER_THAN TOK_LESS_EQUAL TOK_GREATER_EQUAL TOK_EQUAL
+%left TOK_ADD TOK_SUB
+%left TOK_MUL TOK_DIV TOK_MOD
+%right UNARY_OP
+
+%%
+
+// ----------------------------------------------------------------------
+start
+// ----------------------------------------------------------------------
+: expr
+{
+ parseResult = $1;
+}
+;
+
+// ----------------------------------------------------------------------
+expr
+// ----------------------------------------------------------------------
+: binary
+{
+ $$ = $1;
+}
+;
+
+// ----------------------------------------------------------------------
+binary
+// ----------------------------------------------------------------------
+: binary TOK_LESS_THAN binary
+{
+ $$ = new BinaryNode(BinOpLess, parseDataFactory, $1, $3);
+}
+| binary TOK_GREATER_THAN binary
+{
+ $$ = new BinaryNode(BinOpGreater, parseDataFactory, $1, $3);
+}
+| binary TOK_LESS_EQUAL binary
+{
+ $$ = new BinaryNode(BinOpLessEq, parseDataFactory, $1, $3);
+}
+| binary TOK_GREATER_EQUAL binary
+{
+ $$ = new BinaryNode(BinOpGrEq, parseDataFactory, $1, $3);
+}
+| binary TOK_EQUAL binary
+{
+ $$ = new BinaryNode(BinOpEq, parseDataFactory, $1, $3);
+}
+| binary TOK_OR binary
+{
+ $$ = new BinaryNode(BinOpOr, parseDataFactory, $1, $3);
+}
+| binary TOK_AND binary
+{
+ $$ = new BinaryNode(BinOpAnd, parseDataFactory, $1, $3);
+}
+| binary TOK_MUL binary
+{
+ $$ = new BinaryNode(BinOpMul, parseDataFactory, $1, $3);
+}
+| binary TOK_DIV binary
+{
+ $$ = new BinaryNode(BinOpDiv, parseDataFactory, $1, $3);
+}
+| binary TOK_MOD binary
+{
+ $$ = new BinaryNode(BinOpMod, parseDataFactory, $1, $3);
+}
+| binary TOK_ADD binary
+{
+ $$ = new BinaryNode(BinOpAdd, parseDataFactory, $1, $3);
+}
+| binary TOK_SUB binary
+{
+ $$ = new BinaryNode(BinOpSub, parseDataFactory, $1, $3);
+}
+| unary
+{
+ $$ = $1;
+}
+;
+
+// ----------------------------------------------------------------------
+unary
+// ----------------------------------------------------------------------
+: TOK_LPAREN expr TOK_RPAREN
+{
+ $$ = $2;
+}
+| TOK_SUB unary %prec UNARY_OP
+{
+ $$ = new UnaryNode(UnaryOpNeg, parseDataFactory, $2);
+}
+| TOK_NOT unary %prec UNARY_OP
+{
+ $$ = new UnaryNode(UnaryOpNot, parseDataFactory, $2);
+}
+| TOK_INTEGER_LITERAL
+{
+ IntegerTokPtr intVal = IntegerTokPtr::dynamicCast($1);
+ assert(intVal);
+ $$ = new DataNode(parseDataFactory->createInteger(intVal->v, true));
+}
+| TOK_FLOATING_POINT_LITERAL
+{
+ FloatingTokPtr floatVal = FloatingTokPtr::dynamicCast($1);
+ assert(floatVal);
+ $$ = new DataNode(parseDataFactory->createDouble(floatVal->v, true));
+}
+| TOK_STRING_LITERAL
+{
+ StringTokPtr stringVal = StringTokPtr::dynamicCast($1);
+ assert(stringVal);
+ $$ = new DataNode(parseDataFactory->createString(stringVal->v, true));
+}
+| TOK_TRUE
+{
+ $$ = new DataNode(parseDataFactory->createBoolean(true, true));
+}
+| TOK_FALSE
+{
+ $$ = new DataNode(parseDataFactory->createBoolean(false, true));
+}
+| TOK_NIL
+{
+ $$ = new DataNode(parseDataFactory->createNil(true));
+}
+| identifier
+{
+ IdentifierTokPtr listVal = IdentifierTokPtr::dynamicCast($1);
+ assert(listVal);
+ $$ = new IdentNode(listVal->v);
+}
+| constant
+{
+ StringTokPtr stringVal = StringTokPtr::dynamicCast($1);
+ assert(stringVal);
+ $$ = new ConstantNode(stringVal->v);
+}
+;
+
+// ----------------------------------------------------------------------
+identifier
+// ----------------------------------------------------------------------
+: identifier '.' TOK_IDENTIFIER
+{
+ IdentifierTokPtr listVal = IdentifierTokPtr::dynamicCast($1);
+ assert(listVal);
+ StringTokPtr stringVal = StringTokPtr::dynamicCast($3);
+ assert(stringVal);
+ listVal->v.push_back(stringVal->v);
+ $$ = $1;
+}
+| TOK_IDENTIFIER
+{
+ StringTokPtr stringVal = StringTokPtr::dynamicCast($1);
+ assert(stringVal);
+ IdentifierTokPtr listVal = new IdentifierTok;
+ listVal->v.push_back(stringVal->v);
+ $$ = listVal;
+}
+;
+
+// ----------------------------------------------------------------------
+constant
+// ----------------------------------------------------------------------
+: constant TOK_SCOPE_DELIMITER TOK_IDENTIFIER
+{
+ StringTokPtr stringVal = StringTokPtr::dynamicCast($1);
+ assert(stringVal);
+ StringTokPtr idVal = StringTokPtr::dynamicCast($3);
+ assert(idVal);
+ stringVal->v.append("::" + idVal->v);
+ $$ = $1;
+}
+| TOK_SCOPE_DELIMITER TOK_IDENTIFIER
+{
+ StringTokPtr idVal = StringTokPtr::dynamicCast($2);
+ assert(idVal);
+ StringTokPtr stringVal = new StringTok;
+ stringVal->v.append("::" + idVal->v);
+ $$ = stringVal;
+}
+;
+
+%%
diff --git a/cpp/src/Transform/GrammarUtil.h b/cpp/src/Transform/GrammarUtil.h
new file mode 100644
index 00000000000..9c0d4389491
--- /dev/null
+++ b/cpp/src/Transform/GrammarUtil.h
@@ -0,0 +1,144 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef FREEZE_GRAMMAR_UTIL_H
+#define FREEZE_GRAMMAR_UTIL_H
+
+#include <Transform/Node.h>
+#include <Transform/Parser.h>
+
+namespace Transform
+{
+
+extern DataFactoryPtr parseDataFactory;
+extern ErrorReporterPtr parseErrorReporter;
+extern NodePtr parseResult;
+extern int parseLine;
+
+int getInput(char*, int);
+
+class StringTok;
+class IdentifierTok;
+class BoolTok;
+class IntegerTok;
+class FloatingTok;
+
+typedef ::IceUtil::Handle<StringTok> StringTokPtr;
+typedef ::IceUtil::Handle<IdentifierTok> IdentifierTokPtr;
+typedef ::IceUtil::Handle<BoolTok> BoolTokPtr;
+typedef ::IceUtil::Handle<IntegerTok> IntegerTokPtr;
+typedef ::IceUtil::Handle<FloatingTok> FloatingTokPtr;
+
+// ----------------------------------------------------------------------
+// Token
+// ----------------------------------------------------------------------
+
+class Token : public Node
+{
+public:
+
+ Token() { }
+ virtual DataPtr evaluate(SymbolTable&) { return 0; }
+ virtual void print(std::ostream&) const {}
+};
+
+// ----------------------------------------------------------------------
+// StringTok
+// ----------------------------------------------------------------------
+
+class StringTok : public Token
+{
+public:
+
+ StringTok() { }
+
+ std::string v;
+};
+
+// ----------------------------------------------------------------------
+// IdentifierTok
+// ----------------------------------------------------------------------
+
+class IdentifierTok : public Token
+{
+public:
+
+ IdentifierTok() { }
+ Identifier v;
+};
+
+// ----------------------------------------------------------------------
+// BoolTok
+// ----------------------------------------------------------------------
+
+class BoolTok : public Token
+{
+public:
+
+ BoolTok() { }
+ bool v;
+};
+
+// ----------------------------------------------------------------------
+// IntegerTok
+// ----------------------------------------------------------------------
+
+class IntegerTok : public Token
+{
+public:
+
+ IntegerTok() { }
+ IceUtil::Int64 v;
+};
+
+// ----------------------------------------------------------------------
+// FloatingTok
+// ----------------------------------------------------------------------
+
+class FloatingTok : public Token
+{
+public:
+
+ FloatingTok() { }
+ double v;
+};
+
+} // End of namespace Transform
+
+//
+// Stuff for flex and bison
+//
+
+#define YYSTYPE Transform::NodePtr
+#define YY_DECL int transform_lex(YYSTYPE* yylvalp)
+YY_DECL;
+int transform_parse();
+
+//
+// I must set the initial stack depth to the maximum stack depth to
+// disable bison stack resizing. The bison stack resizing routines use
+// simple malloc/alloc/memcpy calls, which do not work for the
+// YYSTYPE, since YYSTYPE is a C++ type, with constructor, destructor,
+// assignment operator, etc.
+//
+#define YYMAXDEPTH 20000 // 20000 should suffice. Bison default is 10000 as maximum.
+#define YYINITDEPTH YYMAXDEPTH // Initial depth is set to max depth, for the reasons described above.
+
+//
+// Newer bison versions allow to disable stack resizing by defining
+// yyoverflow.
+//
+#define yyoverflow(a, b, c, d, e, f) transform_error(a)
+
+#endif
diff --git a/cpp/src/Transform/Makefile b/cpp/src/Transform/Makefile
new file mode 100644
index 00000000000..2ee037204cb
--- /dev/null
+++ b/cpp/src/Transform/Makefile
@@ -0,0 +1,74 @@
+# **********************************************************************
+#
+# Copyright (c) 2003
+# ZeroC, Inc.
+# Billerica, MA, USA
+#
+# All Rights Reserved.
+#
+# Ice is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License version 2 as published by
+# the Free Software Foundation.
+#
+# **********************************************************************
+
+top_srcdir = ../..
+
+LIBFILENAME = $(call mklibfilename,Transform,$(VERSION))
+SONAME = $(call mksoname,Transform,$(SOVERSION))
+LIBNAME = $(call mklibname,Transform)
+
+TRANSFORMDB = $(top_srcdir)/bin/transformdb
+
+TARGETS = $(libdir)/$(LIBFILENAME) $(libdir)/$(SONAME) $(libdir)/$(LIBNAME) $(TRANSFORMDB)
+
+OBJS = Grammar.o \
+ Scanner.o \
+ Analyzer.o \
+ Transformer.o \
+ Data.o \
+ Error.o \
+ Exception.o \
+ Node.o \
+ TransformUtil.o \
+ Parser.o
+
+TRANSFORM_OBJS = TransformDB.o
+
+SRCS = $(OBJS:.o=.cpp) $(TRANSFORM_OBJS:.o=.cpp)
+
+HDIR = $(includedir)/Transform
+
+include $(top_srcdir)/config/Make.rules
+
+CPPFLAGS := -I.. $(CPPFLAGS) -DTRANSFORM_API_EXPORTS $(DB_FLAGS)
+
+$(libdir)/$(LIBFILENAME): $(OBJS)
+ rm -f $@
+ $(call mkshlib,$@,$(SONAME),$(OBJS),$(LINKWITH))
+
+$(libdir)/$(SONAME): $(libdir)/$(LIBFILENAME)
+ rm -f $@
+ ln -s $(LIBFILENAME) $@
+
+$(libdir)/$(LIBNAME): $(libdir)/$(SONAME)
+ rm -f $@
+ ln -s $(SONAME) $@
+
+$(TRANSFORMDB): $(TRANSFORM_OBJS)
+ rm -f $@
+ $(CXX) $(LDFLAGS) -o $@ $(TRANSFORM_OBJS) -lTransform -lSlice -lIceXML $(LIBS) $(DB_LIBS)
+
+clean::
+ rm -f Grammar.cpp Grammar.h
+ rm -f Scanner.cpp
+
+install:: all
+ $(INSTALL_LIBRARY) $(libdir)/$(LIBFILENAME) $(install_libdir)
+ rm -f $(install_libdir)/$(SONAME)
+ ln -s $(LIBFILENAME) $(install_libdir)/$(SONAME)
+ rm -f $(install_libdir)/$(LIBNAME)
+ ln -s $(SONAME) $(install_libdir)/$(LIBNAME)
+ $(INSTALL_PROGRAM) $(TRANSFORMDB) $(install_bindir)
+
+include .depend
diff --git a/cpp/src/Transform/Node.cpp b/cpp/src/Transform/Node.cpp
new file mode 100644
index 00000000000..0c4948f72dd
--- /dev/null
+++ b/cpp/src/Transform/Node.cpp
@@ -0,0 +1,464 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Node.h>
+
+using namespace std;
+
+ostream&
+operator<<(ostream& os, const Transform::Identifier& id)
+{
+ for(Transform::Identifier::const_iterator p = id.begin(); p != id.end(); ++p)
+ {
+ if(p != id.begin())
+ {
+ os << '.';
+ }
+ os << *p;
+ }
+ return os;
+}
+
+//
+// EvaluateException
+//
+Transform::EvaluateException::EvaluateException(const char* file, int line, const string& reason) :
+ IceUtil::Exception(file, line), _reason(reason)
+{
+}
+
+string
+Transform::EvaluateException::ice_name() const
+{
+ return "Transform::EvaluateException";
+}
+
+void
+Transform::EvaluateException::ice_print(ostream& out) const
+{
+ IceUtil::Exception::ice_print(out);
+ out << ":\nerror occurred while evaluating expression";
+ if(!_reason.empty())
+ {
+ out << ":\n" << _reason;
+ }
+}
+
+IceUtil::Exception*
+Transform::EvaluateException::ice_clone() const
+{
+ return new EvaluateException(ice_file(), ice_line(), _reason);
+}
+
+void
+Transform::EvaluateException::ice_throw() const
+{
+ throw *this;
+}
+
+string
+Transform::EvaluateException::reason() const
+{
+ return _reason;
+}
+
+//
+// SymbolTable
+//
+Transform::SymbolTable::~SymbolTable()
+{
+}
+
+//
+// Node
+//
+Transform::Node::~Node()
+{
+}
+
+//
+// BinaryNode
+//
+Transform::BinaryNode::BinaryNode(BinaryOperator op, const DataFactoryPtr& factory, const NodePtr& left,
+ const NodePtr& right) :
+ _op(op), _factory(factory), _left(left), _right(right)
+{
+}
+
+Transform::DataPtr
+Transform::BinaryNode::evaluate(SymbolTable& st)
+{
+ DataPtr result;
+
+ switch(_op)
+ {
+ case BinOpOr:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ if(leftValue->booleanValue())
+ {
+ result = leftValue;
+ }
+ else
+ {
+ result = _right->evaluate(st);
+ }
+ break;
+ }
+
+ case BinOpAnd:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ if(!leftValue->booleanValue())
+ {
+ result = leftValue;
+ }
+ else
+ {
+ result = _right->evaluate(st);
+ }
+ break;
+ }
+
+ case BinOpMul:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ IntegerDataPtr ileft = IntegerDataPtr::dynamicCast(leftValue);
+ IntegerDataPtr iright = IntegerDataPtr::dynamicCast(rightValue);
+ if(ileft && iright)
+ {
+ result = _factory->createInteger(leftValue->integerValue() * rightValue->integerValue(), true);
+ }
+ else
+ {
+ result = _factory->createDouble(leftValue->doubleValue(true) * rightValue->doubleValue(true), true);
+ }
+ break;
+ }
+
+ case BinOpDiv:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ IntegerDataPtr ileft = IntegerDataPtr::dynamicCast(leftValue);
+ IntegerDataPtr iright = IntegerDataPtr::dynamicCast(rightValue);
+ if(ileft && iright)
+ {
+ result = _factory->createInteger(leftValue->integerValue() / rightValue->integerValue(), true);
+ }
+ else
+ {
+ result = _factory->createDouble(leftValue->doubleValue(true) / rightValue->doubleValue(true), true);
+ }
+ break;
+ }
+
+ case BinOpMod:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ result = _factory->createInteger(leftValue->integerValue() % rightValue->integerValue(), true);
+ break;
+ }
+
+ case BinOpAdd:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ IntegerDataPtr ileft = IntegerDataPtr::dynamicCast(leftValue);
+ IntegerDataPtr iright = IntegerDataPtr::dynamicCast(rightValue);
+ if(ileft && iright)
+ {
+ result = _factory->createInteger(leftValue->integerValue() + rightValue->integerValue(), true);
+ }
+ else
+ {
+ result = _factory->createDouble(leftValue->doubleValue(true) + rightValue->doubleValue(true), true);
+ }
+ break;
+ }
+
+ case BinOpSub:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ IntegerDataPtr ileft = IntegerDataPtr::dynamicCast(leftValue);
+ IntegerDataPtr iright = IntegerDataPtr::dynamicCast(rightValue);
+ if(ileft && iright)
+ {
+ result = _factory->createInteger(leftValue->integerValue() - rightValue->integerValue(), true);
+ }
+ else
+ {
+ result = _factory->createDouble(leftValue->doubleValue(true) - rightValue->doubleValue(true), true);
+ }
+ break;
+ }
+
+ case BinOpLess:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ bool b = leftValue < rightValue;
+ result = _factory->createBoolean(b, true);
+ break;
+ }
+
+ case BinOpGreater:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ bool b = (leftValue < rightValue) || (leftValue == rightValue);
+ result = _factory->createBoolean(!b, true);
+ break;
+ }
+
+ case BinOpLessEq:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ bool b = (leftValue < rightValue) || (leftValue == rightValue);
+ result = _factory->createBoolean(b, true);
+ break;
+ }
+
+ case BinOpGrEq:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ bool b = leftValue < rightValue;
+ result = _factory->createBoolean(!b, true);
+ break;
+ }
+
+ case BinOpEq:
+ {
+ DataPtr leftValue = _left->evaluate(st);
+ DataPtr rightValue = _right->evaluate(st);
+ bool b = leftValue == rightValue;
+ result = _factory->createBoolean(b, true);
+ break;
+ }
+ }
+
+ if(!result)
+ {
+ throw EvaluateException(__FILE__, __LINE__, "invalid operands to operator " + opToString(_op));
+ }
+
+ return result;
+}
+
+void
+Transform::BinaryNode::print(ostream& os) const
+{
+ os << opToString(_op) << ": left=";
+ _left->print(os);
+ os << ", right=";
+ _right->print(os);
+}
+
+string
+Transform::BinaryNode::opToString(BinaryOperator op)
+{
+ switch(op)
+ {
+ case BinOpOr:
+ return "OR";
+
+ case BinOpAnd:
+ return "AND";
+
+ case BinOpMul:
+ return "*";
+
+ case BinOpDiv:
+ return "/";
+
+ case BinOpMod:
+ return "%";
+
+ case BinOpAdd:
+ return "+";
+
+ case BinOpSub:
+ return "-";
+
+ case BinOpLess:
+ return "<";
+
+ case BinOpGreater:
+ return ">";
+
+ case BinOpLessEq:
+ return "<=";
+
+ case BinOpGrEq:
+ return ">=";
+
+ case BinOpEq:
+ return "==";
+ }
+
+ assert(false);
+ return string();
+}
+
+//
+// UnaryNode
+//
+Transform::UnaryNode::UnaryNode(UnaryOperator op, const DataFactoryPtr& factory, const NodePtr& right) :
+ _op(op), _factory(factory), _right(right)
+{
+}
+
+Transform::DataPtr
+Transform::UnaryNode::evaluate(SymbolTable& st)
+{
+ DataPtr result;
+
+ switch(_op)
+ {
+ case UnaryOpNeg:
+ {
+ DataPtr rightValue = _right->evaluate(st);
+ IntegerDataPtr iright = IntegerDataPtr::dynamicCast(rightValue);
+ if(iright)
+ {
+ result = _factory->createInteger(-rightValue->integerValue(), true);
+ }
+ else
+ {
+ result = _factory->createDouble(-rightValue->doubleValue(), true);
+ }
+ break;
+ }
+
+ case UnaryOpNot:
+ {
+ DataPtr rightValue = _right->evaluate(st);
+ result = _factory->createBoolean(!rightValue->booleanValue(), true);
+ break;
+ }
+ }
+
+ if(!result)
+ {
+ throw EvaluateException(__FILE__, __LINE__, "invalid operand to operator " + opToString(_op));
+ }
+
+ return result;
+}
+
+void
+Transform::UnaryNode::print(ostream& os) const
+{
+ os << opToString(_op) << ": right=";
+ _right->print(os);
+}
+
+string
+Transform::UnaryNode::opToString(UnaryOperator op)
+{
+ switch(op)
+ {
+ case UnaryOpNeg:
+ return "-";
+
+ case UnaryOpNot:
+ return "!";
+ }
+
+ assert(false);
+ return string();
+}
+
+//
+// DataNode
+//
+Transform::DataNode::DataNode(const DataPtr& data) :
+ _data(data)
+{
+}
+
+Transform::DataPtr
+Transform::DataNode::evaluate(SymbolTable&)
+{
+ return _data;
+}
+
+void
+Transform::DataNode::print(ostream& os) const
+{
+ _data->print(os);
+}
+
+//
+// IdentNode
+//
+Transform::IdentNode::IdentNode(const Identifier& value) :
+ _value(value)
+{
+}
+
+Transform::DataPtr
+Transform::IdentNode::evaluate(SymbolTable& st)
+{
+ DataPtr result = st.getValue(_value);
+ if(!result)
+ {
+ ostringstream ostr;
+ print(ostr);
+ throw EvaluateException(__FILE__, __LINE__, "unknown identifier `" + ostr.str() + "'");
+ }
+ return result;
+}
+
+void
+Transform::IdentNode::print(ostream& os) const
+{
+ os << _value;
+}
+
+Transform::Identifier
+Transform::IdentNode::getValue() const
+{
+ return _value;
+}
+
+//
+// ConstantNode
+//
+Transform::ConstantNode::ConstantNode(const string& value) :
+ _value(value)
+{
+}
+
+Transform::DataPtr
+Transform::ConstantNode::evaluate(SymbolTable& st)
+{
+ DataPtr result = st.getConstantValue(_value);
+ if(!result)
+ {
+ throw EvaluateException(__FILE__, __LINE__, "unknown constant `" + _value + "'");
+ }
+ return result;
+}
+
+void
+Transform::ConstantNode::print(ostream& os) const
+{
+ os << _value;
+}
diff --git a/cpp/src/Transform/Node.h b/cpp/src/Transform/Node.h
new file mode 100644
index 00000000000..860448b8017
--- /dev/null
+++ b/cpp/src/Transform/Node.h
@@ -0,0 +1,166 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_NODE_H
+#define TRANSFORM_NODE_H
+
+#include <Transform/Data.h>
+
+namespace Transform
+{
+
+class Node;
+typedef IceUtil::Handle<Node> NodePtr;
+
+typedef std::vector<std::string> Identifier;
+
+class EvaluateException : public IceUtil::Exception
+{
+public:
+
+ EvaluateException(const char*, int, const std::string&);
+ virtual std::string ice_name() const;
+ virtual void ice_print(std::ostream&) const;
+ virtual IceUtil::Exception* ice_clone() const;
+ virtual void ice_throw() const;
+ std::string reason() const;
+
+private:
+
+ std::string _reason;
+};
+
+class SymbolTable
+{
+public:
+
+ virtual ~SymbolTable();
+
+ virtual DataPtr getValue(const Identifier&) const = 0;
+ virtual DataPtr getConstantValue(const std::string&) const = 0;
+};
+
+class Node : public IceUtil::SimpleShared
+{
+public:
+
+ virtual ~Node();
+
+ virtual DataPtr evaluate(SymbolTable&) = 0;
+
+ virtual void print(std::ostream&) const = 0;
+};
+
+enum BinaryOperator
+{
+ BinOpOr, BinOpAnd,
+ BinOpMul, BinOpDiv, BinOpMod,
+ BinOpAdd, BinOpSub,
+ BinOpLess, BinOpGreater, BinOpLessEq, BinOpGrEq, BinOpEq
+};
+
+class BinaryNode : public Node
+{
+public:
+
+ BinaryNode(BinaryOperator, const DataFactoryPtr&, const NodePtr&, const NodePtr&);
+
+ virtual DataPtr evaluate(SymbolTable&);
+
+ virtual void print(std::ostream&) const;
+
+private:
+
+ static std::string opToString(BinaryOperator);
+
+ BinaryOperator _op;
+ DataFactoryPtr _factory;
+ NodePtr _left;
+ NodePtr _right;
+};
+
+enum UnaryOperator { UnaryOpNeg, UnaryOpNot };
+
+class UnaryNode : public Node
+{
+public:
+
+ UnaryNode(UnaryOperator, const DataFactoryPtr&, const NodePtr&);
+
+ virtual DataPtr evaluate(SymbolTable&);
+
+ virtual void print(std::ostream&) const;
+
+private:
+
+ static std::string opToString(UnaryOperator);
+
+ UnaryOperator _op;
+ DataFactoryPtr _factory;
+ NodePtr _right;
+};
+
+class DataNode : public Node
+{
+public:
+
+ DataNode(const DataPtr&);
+
+ virtual DataPtr evaluate(SymbolTable&);
+
+ virtual void print(std::ostream&) const;
+
+private:
+
+ DataPtr _data;
+};
+
+class IdentNode : public Node
+{
+public:
+
+ IdentNode(const Identifier&);
+
+ virtual DataPtr evaluate(SymbolTable&);
+
+ virtual void print(std::ostream&) const;
+
+ Identifier getValue() const;
+
+private:
+
+ Identifier _value;
+};
+typedef IceUtil::Handle<IdentNode> IdentNodePtr;
+
+class ConstantNode : public Node
+{
+public:
+
+ ConstantNode(const std::string&);
+
+ virtual DataPtr evaluate(SymbolTable&);
+
+ virtual void print(std::ostream&) const;
+
+private:
+
+ std::string _value;
+};
+
+} // End of namespace Transform
+
+std::ostream& operator<<(std::ostream&, const Transform::Identifier&);
+
+#endif
diff --git a/cpp/src/Transform/Parser.cpp b/cpp/src/Transform/Parser.cpp
new file mode 100644
index 00000000000..e7a551339cb
--- /dev/null
+++ b/cpp/src/Transform/Parser.cpp
@@ -0,0 +1,75 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Parser.h>
+#include <Transform/GrammarUtil.h>
+#include <IceUtil/Mutex.h>
+
+using namespace std;
+
+Transform::DataFactoryPtr Transform::parseDataFactory;
+Transform::ErrorReporterPtr Transform::parseErrorReporter;
+Transform::NodePtr Transform::parseResult;
+int Transform::parseLine;
+
+static string _input;
+static string::size_type _pos;
+static IceUtil::Mutex _parserMutex;
+
+//
+// Parser
+//
+Transform::NodePtr
+Transform::Parser::parse(const string& expr, const DataFactoryPtr& factory, const ErrorReporterPtr& errorReporter)
+{
+ //
+ // The bison grammar is not thread-safe.
+ //
+ IceUtil::Mutex::Lock sync(_parserMutex);
+
+ parseDataFactory = factory;
+ parseErrorReporter = errorReporter;
+ parseLine = 1;
+
+ parseErrorReporter->setExpression(expr);
+
+ _input = expr;
+ _pos = 0;
+
+ int status = transform_parse();
+ if(status != 0)
+ {
+ parseResult = 0;
+ }
+
+ parseErrorReporter->clearExpression();
+ parseErrorReporter = 0;
+
+ return parseResult;
+}
+
+int
+Transform::getInput(char* buf, int maxSize)
+{
+ if(_pos < _input.length())
+ {
+ buf[0] = _input[_pos];
+ _pos++;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
diff --git a/cpp/src/Transform/Parser.h b/cpp/src/Transform/Parser.h
new file mode 100644
index 00000000000..c7791252cf2
--- /dev/null
+++ b/cpp/src/Transform/Parser.h
@@ -0,0 +1,33 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_PARSER_H
+#define TRANSFORM_PARSER_H
+
+#include <Transform/Node.h>
+#include <string>
+
+namespace Transform
+{
+
+class Parser
+{
+public:
+
+ static NodePtr parse(const std::string&, const DataFactoryPtr&, const ErrorReporterPtr&);
+};
+
+} // End of namespace Transform
+
+#endif
diff --git a/cpp/src/Transform/Scanner.l b/cpp/src/Transform/Scanner.l
new file mode 100644
index 00000000000..b870db79ff9
--- /dev/null
+++ b/cpp/src/Transform/Scanner.l
@@ -0,0 +1,375 @@
+%{
+
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/GrammarUtil.h> // Before Grammar.h, so that YYSTYPE is defined
+#include <Transform/Grammar.h>
+#include <IceUtil/InputUtil.h>
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <map>
+
+#ifdef _WIN32
+ // I get these warnings from some flex versions:
+ // warning C4003: not enough actual parameters for macro 'yywrap'
+# pragma warning( disable : 4003 )
+#endif
+
+using namespace std;
+using namespace Transform;
+
+namespace Transform
+{
+
+typedef map<string, int> KeywordMap;
+static KeywordMap keywordMap;
+
+void initScanner();
+int checkKeyword(const string&);
+StringTokPtr parseString(char);
+
+}
+
+#define YY_USER_INIT initScanner();
+
+#define YY_INPUT(buf, result, max_size) { result = getInput(buf, max_size); }
+%}
+
+%option noyywrap
+%option never-interactive
+%option prefix="transform_"
+%option outfile="lex.yy.c"
+
+identifier [[:alpha:]_][[:alnum:]_]*
+integer_constant (\+|-)?((0[0-7]+)|(0x[[:xdigit:]]+)|([[:digit:]]+))
+fractional_constant ([[:digit:]]*\.[[:digit:]]+)|([[:digit:]]+\.)
+exponent_part (e|E)(\+|-)?[[:digit:]]+
+floating_literal (({fractional_constant}{exponent_part}?)|([[:digit:]]+{exponent_part}))[fF]?
+
+%%
+
+"//" {
+ // C++-style comment
+ int c;
+ do
+ {
+ c = yyinput();
+ if(c == '\n')
+ {
+ parseLine++;
+ }
+ }
+ while(c != '\n' && c != EOF);
+}
+
+"/*" {
+ // C-style comment
+ while(true)
+ {
+ int c = yyinput();
+ if(c == '\n')
+ {
+ parseLine++;
+ }
+ else if(c == '*')
+ {
+ int next = yyinput();
+ if(next == '/')
+ {
+ break;
+ }
+ else
+ {
+ unput(next);
+ }
+ }
+ else if(c == EOF)
+ {
+ parseErrorReporter->expressionSyntaxError("EOF in comment");
+ break;
+ }
+ }
+}
+
+{identifier} {
+ StringTokPtr ident = new StringTok;
+ ident->v = yytext;
+ *yylvalp = ident;
+ return checkKeyword(ident->v);
+}
+
+\" {
+ StringTokPtr str = parseString('"');
+ *yylvalp = str;
+ return TOK_STRING_LITERAL;
+}
+
+\' {
+ StringTokPtr str = parseString('\'');
+ *yylvalp = str;
+ return TOK_STRING_LITERAL;
+}
+
+{integer_constant} {
+ IntegerTokPtr itp = new IntegerTok;
+ *yylvalp = itp;
+ errno = 0;
+ itp->v = IceUtil::strToInt64(yytext, 0, 0);
+ if(errno == ERANGE && (itp->v == IceUtil::Int64Min || itp->v == IceUtil::Int64Max))
+ {
+ string msg = "integer constant `";
+ msg += yytext;
+ msg += "' out of range";
+ parseErrorReporter->expressionSyntaxError(msg);
+ }
+ return TOK_INTEGER_LITERAL;
+}
+
+{floating_literal} {
+ errno = 0;
+ FloatingTokPtr ftp = new FloatingTok;
+ *yylvalp = ftp;
+ string literal(yytext);
+ char lastChar = literal[literal.size() - 1];
+ if(lastChar == 'f' || lastChar == 'F')
+ {
+ literal = literal.substr(0, literal.size() - 1); // Clobber trailing 'f' or 'F' suffix
+ }
+ ftp->v = strtod(literal.c_str(), 0);
+ if((ftp->v == HUGE_VAL || ftp->v == -HUGE_VAL) && errno == ERANGE)
+ {
+ string msg = "floating-point constant `";
+ msg += yytext;
+ msg += "' too large (overflow)";
+ parseErrorReporter->expressionSyntaxError(msg);
+ }
+ else if(ftp->v == 0 && errno == ERANGE)
+ {
+ string msg = "floating-point constant `";
+ msg += yytext;
+ msg += "' too small (underflow)";
+ parseErrorReporter->expressionSyntaxError(msg);
+ }
+ return TOK_FLOATING_POINT_LITERAL;
+}
+
+[[:space:]] {
+ // Igore white-space
+
+ if(yytext[0] == '\n')
+ {
+ parseLine++;
+ }
+}
+
+"<" return TOK_LESS_THAN;
+">" return TOK_GREATER_THAN;
+"<=" return TOK_LESS_EQUAL;
+">=" return TOK_GREATER_EQUAL;
+"==" return TOK_EQUAL;
+"+" return TOK_ADD;
+"-" return TOK_SUB;
+"*" return TOK_MUL;
+"/" return TOK_DIV;
+"%" return TOK_MOD;
+"(" return TOK_LPAREN;
+")" return TOK_RPAREN;
+"[" return TOK_LBRACKET;
+"]" return TOK_RBRACKET;
+"::" return TOK_SCOPE_DELIMITER;
+
+. {
+ return yytext[0];
+}
+
+%%
+
+namespace Transform
+{
+
+void
+initScanner()
+{
+ keywordMap["true"] = TOK_TRUE;
+ keywordMap["false"] = TOK_FALSE;
+ keywordMap["and"] = TOK_AND;
+ keywordMap["or"] = TOK_OR;
+ keywordMap["not"] = TOK_NOT;
+ keywordMap["nil"] = TOK_NIL;
+}
+
+int
+checkKeyword(const string& id)
+{
+ KeywordMap::const_iterator pos = keywordMap.find(id);
+ if(pos != keywordMap.end())
+ {
+ return pos->second;
+ }
+ return TOK_IDENTIFIER;
+}
+
+StringTokPtr
+parseString(char start)
+{
+ StringTokPtr str = new StringTok;
+ while(true)
+ {
+ char c = static_cast<char>(yyinput());
+ if(c == start)
+ {
+ break;
+ }
+ else if(c == EOF)
+ {
+ parseErrorReporter->expressionSyntaxError("EOF in string");
+ break;
+ }
+ else if(c == '\n')
+ {
+ parseErrorReporter->expressionSyntaxError("newline in string");
+ }
+ else if(c == '\\')
+ {
+ char next = static_cast<char>(yyinput());
+ switch(next)
+ {
+ case '\\':
+ case '"':
+ case '\'':
+ {
+ str->v += next;
+ break;
+ }
+
+ case 'n':
+ {
+ str->v += '\n';
+ break;
+ }
+
+ case 'r':
+ {
+ str->v += '\r';
+ break;
+ }
+
+ case 't':
+ {
+ str->v += '\t';
+ break;
+ }
+
+ case 'v':
+ {
+ str->v += '\v';
+ break;
+ }
+
+ case 'f':
+ {
+ str->v += '\f';
+ break;
+ }
+
+ case 'a':
+ {
+ str->v += '\a';
+ break;
+ }
+
+ case 'b':
+ {
+ str->v += '\b';
+ break;
+ }
+
+ case '?':
+ {
+ str->v += '\?';
+ break;
+ }
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ {
+ static string octalDigits = "01234567";
+ unsigned short us = next - '0';
+ if(octalDigits.find_first_of(next = static_cast<char>(yyinput())) != string::npos)
+ {
+ us = us * 8 + next - '0';
+ if(octalDigits.find_first_of(next = static_cast<char>(yyinput())) != string::npos)
+ {
+ us = us * 8 + next - '0';
+ }
+ else
+ {
+ unput(next);
+ }
+ }
+ else
+ {
+ unput(next);
+ }
+ str->v += static_cast<char>(us);
+ break;
+ }
+ case 'x':
+ {
+ IceUtil::Int64 ull = 0;
+ while(isxdigit(next = static_cast<char>(yyinput())))
+ {
+ ull *= 16;
+ if(isdigit(next))
+ {
+ ull += next - '0';
+ }
+ else if(islower(next))
+ {
+ ull += next - 'a' + 10;
+ }
+ else
+ {
+ ull += next - 'A' + 10;
+ }
+ }
+ unput(next);
+ str->v += static_cast<char>(ull);
+ break;
+ }
+
+ // TODO: add universal character names
+
+ default:
+ {
+ str->v += c;
+ unput(next);
+ }
+ }
+ }
+ else
+ {
+ str->v += c;
+ }
+ }
+
+ return str;
+}
+
+} // End of namespace Transform
diff --git a/cpp/src/Transform/TransformDB.cpp b/cpp/src/Transform/TransformDB.cpp
new file mode 100644
index 00000000000..5fd6e75fa77
--- /dev/null
+++ b/cpp/src/Transform/TransformDB.cpp
@@ -0,0 +1,563 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Slice/Preprocessor.h>
+#include <Transform/Transformer.h>
+#include <Transform/TransformUtil.h>
+#include <db_cxx.h>
+#include <sys/stat.h>
+#include <fstream>
+#include <algorithm>
+
+using namespace std;
+
+#ifdef _WIN32
+# define TRANSFORM_DB_MODE 0
+#else
+# define TRANSFORM_DB_MODE (S_IRUSR | S_IWUSR)
+#endif
+
+static void
+usage(const char* n)
+{
+ cerr << "Usage: " << n << " [options] [dbenv db newdb]\n";
+ cerr <<
+ "Options:\n"
+ "-h, --help Show this message.\n"
+ "-v, --version Display the Ice version.\n"
+ "-DNAME Define NAME as 1.\n"
+ "-DNAME=DEF Define NAME as DEF.\n"
+ "-UNAME Remove any definition for NAME.\n"
+ "-IDIR Put DIR in the include file search path.\n"
+ "-d, --debug Print debug messages.\n"
+ "--ice Permit `Ice' prefix (for building Ice source code only)\n"
+ "-o FILE Output transformation descriptors into the file FILE.\n"
+ " Database transformation is not performed.\n"
+ "-i Ignore incompatible type changes.\n"
+ "-f FILE Execute the transformation descriptors in the file FILE.\n"
+ " Database transformation is not performed.\n"
+ "--old SLICE Load old Slice definitions from the file SLICE.\n"
+ "--new SLICE Load new Slice definitions from the file SLICE.\n"
+ "-e Indicates the database is an Evictor database.\n"
+ "--key TYPE[,TYPE] Specifies the Slice types of the database key. If the\n"
+ " type names have not changed, only one needs to be\n"
+ " specified. Otherwise, the type names are specified as\n"
+ " old-type,new-type.\n"
+ "--value TYPE[,TYPE] Specifies the Slice types of the database value. If the\n"
+ " type names have not changed, only one needs to be\n"
+ " specified. Otherwise, the type names are specified as\n"
+ " old-type,new-type.\n"
+ ;
+ // Note: --case-sensitive is intentionally not shown here!
+}
+
+static bool
+parseSlice(const string& n, const Slice::UnitPtr& u, const vector<string>& files, const string& cppArgs, bool debug)
+{
+ //
+ // Parse the Slice files.
+ //
+ for(vector<string>::const_iterator p = files.begin(); p != files.end(); ++p)
+ {
+ Slice::Preprocessor icecpp(n, *p, cppArgs);
+
+ FILE* cppHandle = icecpp.preprocess(false);
+
+ if(cppHandle == 0)
+ {
+ return false;
+ }
+
+ int status = u->parse(cppHandle, debug);
+
+ if(!icecpp.close())
+ {
+ return false;
+ }
+
+ if(status != EXIT_SUCCESS)
+ {
+ return false;
+ }
+ }
+
+ u->mergeModules();
+
+ return true;
+}
+
+static int
+run(int argc, char** argv, const Ice::CommunicatorPtr& communicator)
+{
+ string cppArgs;
+ vector<string> includePaths;
+ bool debug = false;
+ bool ice = false;
+ bool caseSensitive = false;
+ string outputFile;
+ bool ignoreTypeChanges = false;
+ string inputFile;
+ vector<string> oldSlice;
+ vector<string> newSlice;
+ bool evictor = false;
+ string keyTypeNames;
+ string valueTypeNames;
+ string dbEnvName, dbName, dbNameNew;
+
+ int idx = 1;
+ while(idx < argc)
+ {
+ if(strcmp(argv[idx], "-h") == 0 || strcmp(argv[idx], "--help") == 0)
+ {
+ usage(argv[0]);
+ return EXIT_SUCCESS;
+ }
+ else if(strcmp(argv[idx], "-v") == 0 || strcmp(argv[idx], "--version") == 0)
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+ else if(strncmp(argv[idx], "-D", 2) == 0 || strncmp(argv[idx], "-U", 2) == 0)
+ {
+ cppArgs += ' ';
+ cppArgs += argv[idx];
+
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strncmp(argv[idx], "-I", 2) == 0)
+ {
+ cppArgs += ' ';
+ cppArgs += argv[idx];
+
+ string path = argv[idx] + 2;
+ if(path.length())
+ {
+ includePaths.push_back(path);
+ }
+
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-d") == 0 || strcmp(argv[idx], "--debug") == 0)
+ {
+ debug = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "--ice") == 0)
+ {
+ ice = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "--case-sensitive") == 0)
+ {
+ caseSensitive = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-o") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ outputFile = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "-i") == 0)
+ {
+ ignoreTypeChanges = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "-f") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ inputFile = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--old") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ oldSlice.push_back(argv[idx + 1]);
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--new") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ newSlice.push_back(argv[idx + 1]);
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "-e") == 0)
+ {
+ evictor = true;
+ for(int i = idx ; i + 1 < argc ; ++i)
+ {
+ argv[i] = argv[i + 1];
+ }
+ --argc;
+ }
+ else if(strcmp(argv[idx], "--key") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ keyTypeNames = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(strcmp(argv[idx], "--value") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ valueTypeNames = argv[idx + 1];
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
+ else if(argv[idx][0] == '-')
+ {
+ cerr << argv[0] << ": unknown option `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ ++idx;
+ }
+ }
+
+ if(outputFile.empty() && argc < 4)
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if(argc > 1)
+ {
+ dbEnvName = argv[1];
+ }
+ if(argc > 2)
+ {
+ dbName = argv[2];
+ }
+ if(argc > 3)
+ {
+ dbNameNew = argv[3];
+ }
+
+ Slice::UnitPtr oldUnit = Slice::Unit::createUnit(true, false, ice, caseSensitive);
+ Transform::Destroyer<Slice::UnitPtr> oldD(oldUnit);
+ if(!parseSlice(argv[0], oldUnit, oldSlice, cppArgs, debug))
+ {
+ return EXIT_FAILURE;
+ }
+
+ Slice::UnitPtr newUnit = Slice::Unit::createUnit(true, false, ice, caseSensitive);
+ Transform::Destroyer<Slice::UnitPtr> newD(newUnit);
+ if(!parseSlice(argv[0], newUnit, newSlice, cppArgs, debug))
+ {
+ return EXIT_FAILURE;
+ }
+
+ //
+ // Create the Transformer.
+ //
+ Transform::Transformer transformer(communicator, oldUnit, newUnit, ignoreTypeChanges);
+
+ //
+ // If no input file was provided, then we need to analyze the Slice types.
+ //
+ string descriptors;
+ if(inputFile.empty())
+ {
+ ostringstream out;
+ vector<string> missingTypes;
+ vector<string> analyzeErrors;
+
+ if(evictor)
+ {
+ transformer.analyze(out, missingTypes, analyzeErrors);
+ }
+ else
+ {
+ string oldKeyName, newKeyName, oldValueName, newValueName;
+ string::size_type pos;
+
+ if(keyTypeNames.empty() || valueTypeNames.empty())
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ pos = keyTypeNames.find(',');
+ if(pos == 0 || pos == keyTypeNames.size())
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ if(pos == string::npos)
+ {
+ oldKeyName = keyTypeNames;
+ newKeyName = keyTypeNames;
+ }
+ else
+ {
+ oldKeyName = keyTypeNames.substr(0, pos);
+ newKeyName = keyTypeNames.substr(pos + 1);
+ }
+
+ pos = valueTypeNames.find(',');
+ if(pos == 0 || pos == valueTypeNames.size())
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ if(pos == string::npos)
+ {
+ oldValueName = valueTypeNames;
+ newValueName = valueTypeNames;
+ }
+ else
+ {
+ oldValueName = valueTypeNames.substr(0, pos);
+ newValueName = valueTypeNames.substr(pos + 1);
+ }
+
+ transformer.analyze(oldKeyName, newKeyName, oldValueName, newValueName, out, missingTypes, analyzeErrors);
+ }
+
+ if(!analyzeErrors.empty())
+ {
+ for(vector<string>::const_iterator p = analyzeErrors.begin(); p != analyzeErrors.end(); ++p)
+ {
+ cerr << argv[0] << ": " << *p << endl;
+ }
+ }
+
+ if(!missingTypes.empty())
+ {
+ sort(missingTypes.begin(), missingTypes.end());
+ unique(missingTypes.begin(), missingTypes.end());
+ if(!analyzeErrors.empty())
+ {
+ cerr << endl;
+ }
+ cerr << "The following types had no matching definitions in the new Slice:" << endl;
+ for(vector<string>::const_iterator p = missingTypes.begin(); p != missingTypes.end(); ++p)
+ {
+ cerr << *p << endl;
+ }
+ }
+
+ if(!analyzeErrors.empty())
+ {
+ return EXIT_FAILURE;
+ }
+
+ descriptors = out.str();
+
+ if(!outputFile.empty())
+ {
+ ofstream of(outputFile.c_str());
+ if(!of.good())
+ {
+ cerr << argv[0] << ": unable to open file `" << outputFile << "'" << endl;
+ return EXIT_FAILURE;
+ }
+ of << descriptors;
+ of.close();
+ return EXIT_SUCCESS;
+ }
+ }
+ else
+ {
+ ifstream in(inputFile.c_str());
+ char buff[1024];
+ while(true)
+ {
+ in.read(buff, 1024);
+ descriptors.append(buff, in.gcount());
+ if(in.gcount() < 1024)
+ {
+ break;
+ }
+ }
+ in.close();
+ }
+
+ DbEnv dbEnv(0);
+ Db* db = 0;
+ Db* dbNew = 0;
+ int status = EXIT_SUCCESS;
+ try
+ {
+#ifdef _WIN32
+ //
+ // Berkeley DB may use a different C++ runtime.
+ //
+ dbEnv.set_alloc(::malloc, ::realloc, ::free);
+#endif
+
+ u_int32_t flags = DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_CREATE;
+ dbEnv.open(dbEnvName.c_str(), flags, TRANSFORM_DB_MODE);
+ db = new Db(&dbEnv, 0);
+ db->open(0, dbName.c_str(), 0, DB_BTREE, DB_RDONLY, TRANSFORM_DB_MODE);
+ dbNew = new Db(&dbEnv, 0);
+ dbNew->open(0, dbNameNew.c_str(), 0, DB_BTREE, DB_CREATE | DB_TRUNCATE, TRANSFORM_DB_MODE);
+
+ istringstream istr(descriptors);
+ transformer.transform(istr, db, dbNew, cerr);
+ }
+ catch(const DbException& ex)
+ {
+ cerr << argv[0] << ": database error: " << ex.what() << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ if(db)
+ {
+ db->close(0);
+ delete db;
+ }
+ if(dbNew)
+ {
+ dbNew->close(0);
+ delete dbNew;
+ }
+ dbEnv.close(0);
+ throw;
+ }
+
+ if(db)
+ {
+ db->close(0);
+ delete db;
+ }
+ if(dbNew)
+ {
+ dbNew->close(0);
+ delete dbNew;
+ }
+ dbEnv.close(0);
+
+ return status;
+}
+
+int
+main(int argc, char* argv[])
+{
+ Ice::CommunicatorPtr communicator;
+ int status = EXIT_SUCCESS;
+ try
+ {
+ communicator = Ice::initialize(argc, argv);
+ status = run(argc, argv, communicator);
+ }
+ catch(const Transform::TransformException& ex)
+ {
+ cerr << ex.reason();
+ return EXIT_FAILURE;
+ }
+ catch(const IceUtil::Exception& ex)
+ {
+ cerr << argv[0] << ": " << ex << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(communicator)
+ {
+ communicator->destroy();
+ }
+
+ return status;
+}
diff --git a/cpp/src/Transform/TransformUtil.cpp b/cpp/src/Transform/TransformUtil.cpp
new file mode 100644
index 00000000000..e2f835115a3
--- /dev/null
+++ b/cpp/src/Transform/TransformUtil.cpp
@@ -0,0 +1,33 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/TransformUtil.h>
+
+using namespace std;
+
+string
+Transform::typeName(const Slice::TypePtr& type)
+{
+ Slice::BuiltinPtr b = Slice::BuiltinPtr::dynamicCast(type);
+ if(b)
+ {
+ return b->kindAsString();
+ }
+ else
+ {
+ Slice::ContainedPtr c = Slice::ContainedPtr::dynamicCast(type);
+ assert(c);
+ return c->scoped();
+ }
+}
diff --git a/cpp/src/Transform/TransformUtil.h b/cpp/src/Transform/TransformUtil.h
new file mode 100644
index 00000000000..fab1ef8ecee
--- /dev/null
+++ b/cpp/src/Transform/TransformUtil.h
@@ -0,0 +1,52 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#ifndef TRANSFORM_TRANSFORM_UTIL_H
+#define TRANSFORM_TRANSFORM_UTIL_H
+
+#include <Slice/Parser.h>
+
+namespace Transform
+{
+
+template<class T>
+class Destroyer
+{
+public:
+
+ Destroyer() {}
+ Destroyer(T p) : _p(p) {}
+ ~Destroyer()
+ {
+ if(_p)
+ _p->destroy();
+ }
+
+ void set(T p)
+ {
+ if(_p)
+ _p->destroy();
+ _p = p;
+ }
+
+private:
+
+ T _p;
+};
+
+std::string typeName(const Slice::TypePtr&);
+
+} // End of namespace Transform
+
+#endif
diff --git a/cpp/src/Transform/Transformer.cpp b/cpp/src/Transform/Transformer.cpp
new file mode 100644
index 00000000000..f6f37a790f2
--- /dev/null
+++ b/cpp/src/Transform/Transformer.cpp
@@ -0,0 +1,2156 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Transform/Transformer.h>
+#include <Transform/TransformUtil.h>
+#include <Transform/Data.h>
+#include <Transform/Parser.h>
+#include <Transform/Error.h>
+#include <Transform/Exception.h>
+#include <Transform/Analyzer.h>
+#include <IceXML/Parser.h>
+#include <db_cxx.h>
+#include <stack>
+
+using namespace std;
+
+namespace Transform
+{
+
+class Descriptor;
+typedef IceUtil::Handle<Descriptor> DescriptorPtr;
+
+class TransformDescriptor;
+typedef IceUtil::Handle<TransformDescriptor> TransformDescriptorPtr;
+
+typedef map<string, TransformDescriptorPtr> TransformMap;
+
+class DeleteRecordException {};
+
+class TransformSymbolTable : public SymbolTable
+{
+public:
+
+ TransformSymbolTable(const DataFactoryPtr&, const Slice::UnitPtr&, const Slice::UnitPtr&, const ErrorReporterPtr&,
+ TransformSymbolTable* = 0);
+
+ virtual DataPtr getValue(const Identifier&) const;
+ virtual DataPtr getConstantValue(const string&) const;
+
+ void add(const string&, const DataPtr&);
+
+private:
+
+ DataPtr findValue(const string&);
+
+ DataFactoryPtr _factory;
+ Slice::UnitPtr _old;
+ Slice::UnitPtr _new;
+ ErrorReporterPtr _errorReporter;
+ TransformSymbolTable* _parent;
+ typedef map<string, DataPtr> DataMap;
+ DataMap _dataMap;
+ DataMap _constantCache;
+};
+
+class Descriptor : virtual public IceUtil::SimpleShared
+{
+public:
+
+ virtual ~Descriptor();
+
+ virtual DescriptorPtr parent() const;
+ virtual void addChild(const DescriptorPtr&) = 0;
+ virtual void validate() = 0;
+ virtual void execute(TransformSymbolTable&, DataInterceptor&) = 0;
+
+ virtual DataFactoryPtr factory() const;
+ virtual Slice::UnitPtr oldUnit() const;
+ virtual Slice::UnitPtr newUnit() const;
+ virtual ErrorReporterPtr errorReporter() const;
+
+protected:
+
+ Descriptor(const DescriptorPtr&, int);
+
+ NodePtr parse(const string&) const;
+
+ Slice::TypePtr findType(const Slice::UnitPtr&, const string&);
+
+ DescriptorPtr _parent;
+ int _line;
+};
+
+class SetDescriptor : public Descriptor
+{
+public:
+
+ SetDescriptor(const DescriptorPtr&, int, const string&, const string&, const string&, const string&, bool);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ IdentNodePtr _target;
+ NodePtr _key;
+ string _keyStr;
+ NodePtr _value;
+ string _valueStr;
+ string _type;
+ bool _convert;
+};
+
+class RemoveDescriptor : public Descriptor
+{
+public:
+
+ RemoveDescriptor(const DescriptorPtr&, int, const string&, const string&);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ IdentNodePtr _target;
+ NodePtr _key;
+ string _keyStr;
+};
+
+class DeleteDescriptor : public Descriptor
+{
+public:
+
+ DeleteDescriptor(const DescriptorPtr&, int);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+};
+
+class FailDescriptor : public Descriptor
+{
+public:
+
+ FailDescriptor(const DescriptorPtr&, int, const string&);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ string _message;
+};
+
+class EchoDescriptor : public Descriptor
+{
+public:
+
+ EchoDescriptor(const DescriptorPtr&, int, const string&, const string&);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ string _message;
+ string _value;
+ NodePtr _node;
+};
+
+class ExecutableContainerDescriptor : virtual public Descriptor
+{
+public:
+
+ ExecutableContainerDescriptor(const DescriptorPtr&, int, const string&);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ string _name;
+ vector<DescriptorPtr> _children;
+};
+
+class ConditionalDescriptor : public ExecutableContainerDescriptor
+{
+public:
+
+ ConditionalDescriptor(const DescriptorPtr&, int, const string&);
+
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ string _test;
+ NodePtr _node;
+};
+
+class IterateDescriptor : public ExecutableContainerDescriptor
+{
+public:
+
+ IterateDescriptor(const DescriptorPtr&, int, const string&, const string&, const string&, const string&,
+ const string&);
+
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+private:
+
+ IdentNodePtr _target;
+ string _key;
+ string _value;
+ string _element;
+ string _index;
+};
+
+class TransformDescriptor : public ExecutableContainerDescriptor
+{
+public:
+
+ TransformDescriptor(const DescriptorPtr&, int, const string&, bool);
+
+ string type() const;
+ bool doDefaultTransform() const;
+
+private:
+
+ bool _default;
+ Slice::TypePtr _oldType;
+ Slice::TypePtr _newType;
+};
+
+class InitDescriptor : virtual public ExecutableContainerDescriptor, virtual public DataInitializer
+{
+public:
+
+ InitDescriptor(const DescriptorPtr&, int, const string&);
+
+ virtual void initialize(const DataFactoryPtr&, const DataPtr&, const Ice::CommunicatorPtr&);
+
+ string type() const;
+
+private:
+
+ Slice::TypePtr _type;
+};
+typedef IceUtil::Handle<InitDescriptor> InitDescriptorPtr;
+
+// TODO: Is this class necessary?
+class RecordDescriptor : public ExecutableContainerDescriptor
+{
+public:
+
+ RecordDescriptor(const DescriptorPtr&, int);
+};
+typedef IceUtil::Handle<RecordDescriptor> RecordDescriptorPtr;
+
+class DatabaseDescriptor : public Descriptor
+{
+public:
+
+ DatabaseDescriptor(const DescriptorPtr&, int, const string&, const string&);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+ bool transform(IceInternal::BasicStream&, IceInternal::BasicStream&, IceInternal::BasicStream&,
+ IceInternal::BasicStream&, const TransformMap&);
+
+private:
+
+ Slice::TypePtr _oldKey;
+ Slice::TypePtr _newKey;
+ Slice::TypePtr _oldValue;
+ Slice::TypePtr _newValue;
+ RecordDescriptorPtr _record;
+};
+typedef IceUtil::Handle<DatabaseDescriptor> DatabaseDescriptorPtr;
+
+class TransformerDescriptor : public Descriptor
+{
+public:
+
+ TransformerDescriptor(const DataFactoryPtr&, const Slice::UnitPtr&, const Slice::UnitPtr&, const ErrorReporterPtr&,
+ int);
+
+ virtual void addChild(const DescriptorPtr&);
+ virtual void validate();
+ virtual void execute(TransformSymbolTable&, DataInterceptor&);
+
+ virtual DataFactoryPtr factory() const;
+ virtual Slice::UnitPtr oldUnit() const;
+ virtual Slice::UnitPtr newUnit() const;
+ virtual ErrorReporterPtr errorReporter() const;
+
+ void transform(const Ice::CommunicatorPtr&, Db*, Db*);
+
+private:
+
+ DataFactoryPtr _factory;
+ Slice::UnitPtr _old;
+ Slice::UnitPtr _new;
+ ErrorReporterPtr _errorReporter;
+ DatabaseDescriptorPtr _database;
+ TransformMap _transforms;
+ vector<DescriptorPtr> _children;
+};
+typedef IceUtil::Handle<TransformerDescriptor> TransformerDescriptorPtr;
+
+class DescriptorHandler : public IceXML::Handler
+{
+public:
+
+ DescriptorHandler(const DataFactoryPtr&, const Slice::UnitPtr&, const Slice::UnitPtr&, const ErrorReporterPtr&);
+
+ virtual void startElement(const std::string&, const IceXML::Attributes&, int, int);
+ virtual void endElement(const std::string&, int, int);
+ virtual void characters(const std::string&, int, int);
+ virtual void error(const std::string&, int, int);
+
+ TransformerDescriptorPtr descriptor() const;
+
+private:
+
+ DataFactoryPtr _factory;
+ Slice::UnitPtr _old;
+ Slice::UnitPtr _new;
+ ErrorReporterPtr _errorReporter;
+ DescriptorPtr _current;
+ TransformerDescriptorPtr _transformer;
+};
+
+class TransformInterceptor : public DataInterceptor
+{
+public:
+
+ TransformInterceptor(const DataFactoryPtr&, const ErrorReporterPtr&, const Slice::UnitPtr&,
+ const Slice::UnitPtr&, const TransformMap&);
+
+ virtual bool preTransform(const DataPtr&, const DataPtr&);
+ virtual void postTransform(const DataPtr&, const DataPtr&);
+ virtual ObjectDataMap& getObjectMap();
+
+private:
+
+ DataFactoryPtr _factory;
+ ErrorReporterPtr _errorReporter;
+ Slice::UnitPtr _old;
+ Slice::UnitPtr _new;
+ const TransformMap& _transformMap;
+ ObjectDataMap _objectMap;
+};
+
+} // End of namespace Transform
+
+//
+// TransformSymbolTable
+//
+Transform::TransformSymbolTable::TransformSymbolTable(const DataFactoryPtr& factory, const Slice::UnitPtr& oldUnit,
+ const Slice::UnitPtr& newUnit,
+ const ErrorReporterPtr& errorReporter,
+ TransformSymbolTable* parent) :
+ _factory(factory), _old(oldUnit), _new(newUnit), _errorReporter(errorReporter), _parent(parent)
+{
+}
+
+Transform::DataPtr
+Transform::TransformSymbolTable::getValue(const Identifier& id) const
+{
+ DataPtr result;
+
+ Identifier tmpid = id;
+ string s = tmpid.front();
+ tmpid.erase(tmpid.begin());
+
+ DataMap::const_iterator p = _dataMap.find(s);
+ if(p != _dataMap.end())
+ {
+ result = p->second;
+ }
+
+ if(!result && _parent)
+ {
+ result = _parent->findValue(s);
+ }
+
+ if(!result)
+ {
+ ostringstream ostr;
+ ostr << "invalid identifier `" << id << "'";
+ throw TransformException(__FILE__, __LINE__, ostr.str());
+ }
+
+ for(Identifier::const_iterator p = tmpid.begin(); p != tmpid.end(); ++p)
+ {
+ DataPtr d = result->getMember(*p);
+ if(!d)
+ {
+ ostringstream ostr;
+ ostr << "invalid identifier `" << id << "'";
+ throw TransformException(__FILE__, __LINE__, ostr.str());
+ }
+ result = d;
+ }
+
+ return result;
+}
+
+Transform::DataPtr
+Transform::TransformSymbolTable::getConstantValue(const string& name) const
+{
+ string::size_type pos;
+ Slice::UnitPtr unit;
+ string key;
+
+ DataMap::const_iterator p = _constantCache.find(name);
+ if(p != _constantCache.end())
+ {
+ return p->second;
+ }
+
+ if(_parent)
+ {
+ return _parent->getConstantValue(name);
+ }
+
+ //
+ // Name must start with "::Old" or "::New" to indicate the Slice unit.
+ //
+ pos = name.find("::Old");
+ if(pos == 0)
+ {
+ if(name.length() > 5)
+ {
+ key = name.substr(5);
+ unit = _old;
+ }
+ }
+ else
+ {
+ pos = name.find("::New");
+ if(pos == 0)
+ {
+ if(name.length() > 5)
+ {
+ key = name.substr(5);
+ unit = _new;
+ }
+ }
+ }
+
+ if(key.empty())
+ {
+ throw TransformException(__FILE__, __LINE__, "invalid constant name `" + name + "'");
+ }
+
+ Slice::ContainedList l = unit->findContents(key);
+ if(l.empty())
+ {
+ throw TransformException(__FILE__, __LINE__, "unknown constant `" + name + "'");
+ }
+
+ Slice::EnumeratorPtr e = Slice::EnumeratorPtr::dynamicCast(l.front());
+ Slice::ConstPtr c = Slice::ConstPtr::dynamicCast(l.front());
+ if(!e && !c)
+ {
+ throw TransformException(__FILE__, __LINE__, "`" + name + "' does not refer to a Slice constant or enumerator");
+ }
+
+ DataPtr result;
+
+ if(c)
+ {
+ Slice::TypePtr type = c->type();
+ string value = c->value();
+ Slice::BuiltinPtr b = Slice::BuiltinPtr::dynamicCast(type);
+ if(b)
+ {
+ switch(b->kind())
+ {
+ case Slice::Builtin::KindByte:
+ case Slice::Builtin::KindShort:
+ case Slice::Builtin::KindInt:
+ case Slice::Builtin::KindLong:
+ {
+ string::size_type pos;
+ Ice::Long n;
+ bool success = IceUtil::stringToInt64(value, n, pos);
+ assert(success);
+ result = _factory->createInteger(n, true);
+ break;
+ }
+
+ case Slice::Builtin::KindBool:
+ {
+ result = _factory->createBoolean(value == "true", true);
+ break;
+ }
+
+ case Slice::Builtin::KindFloat:
+ case Slice::Builtin::KindDouble:
+ {
+ double v = strtod(value.c_str(), 0);
+ result = _factory->createDouble(v, true);
+ break;
+ }
+
+ case Slice::Builtin::KindString:
+ {
+ result = _factory->createString(value, true);
+ break;
+ }
+
+ case Slice::Builtin::KindObject:
+ case Slice::Builtin::KindObjectProxy:
+ case Slice::Builtin::KindLocalObject:
+ assert(false);
+ }
+ }
+ else
+ {
+ Slice::EnumPtr en = Slice::EnumPtr::dynamicCast(type);
+ assert(en);
+ Slice::EnumeratorList el = en->getEnumerators();
+ for(Slice::EnumeratorList::iterator p = el.begin(); p != el.end(); ++p)
+ {
+ if((*p)->name() == value)
+ {
+ e = *p;
+ break;
+ }
+ }
+ assert(e);
+ }
+ }
+
+ if(!result)
+ {
+ assert(e);
+ result = _factory->create(e->type(), true);
+ EnumDataPtr ed = EnumDataPtr::dynamicCast(result);
+ assert(ed);
+ ed->setValueAsString(e->name());
+ }
+
+ //
+ // Cache the value.
+ //
+ const_cast<DataMap&>(_constantCache).insert(DataMap::value_type(name, result));
+
+ return result;
+}
+
+void
+Transform::TransformSymbolTable::add(const string& name, const DataPtr& data)
+{
+ DataPtr d = findValue(name);
+ if(d)
+ {
+ throw TransformException(__FILE__, __LINE__, "`" + name + "' is already defined");
+ }
+
+ _dataMap.insert(DataMap::value_type(name, data));
+}
+
+Transform::DataPtr
+Transform::TransformSymbolTable::findValue(const string& name)
+{
+ DataMap::const_iterator p = _dataMap.find(name);
+ if(p != _dataMap.end())
+ {
+ return p->second;
+ }
+
+ if(_parent)
+ {
+ return _parent->findValue(name);
+ }
+
+ return 0;
+}
+
+//
+// Descriptor
+//
+Transform::Descriptor::Descriptor(const DescriptorPtr& parent, int line) :
+ _parent(parent), _line(line)
+{
+}
+
+Transform::Descriptor::~Descriptor()
+{
+}
+
+Transform::DescriptorPtr
+Transform::Descriptor::parent() const
+{
+ return _parent;
+}
+
+Transform::DataFactoryPtr
+Transform::Descriptor::factory() const
+{
+ assert(_parent);
+ return _parent->factory();
+}
+
+Slice::UnitPtr
+Transform::Descriptor::oldUnit() const
+{
+ assert(_parent);
+ return _parent->oldUnit();
+}
+
+Slice::UnitPtr
+Transform::Descriptor::newUnit() const
+{
+ assert(_parent);
+ return _parent->newUnit();
+}
+
+Transform::ErrorReporterPtr
+Transform::Descriptor::errorReporter() const
+{
+ assert(_parent);
+ return _parent->errorReporter();
+}
+
+Transform::NodePtr
+Transform::Descriptor::parse(const string& expr) const
+{
+ return Parser::parse(expr, factory(), errorReporter());
+}
+
+Slice::TypePtr
+Transform::Descriptor::findType(const Slice::UnitPtr& u, const string& type)
+{
+ Slice::TypeList l;
+
+ l = u->lookupType(type, false);
+ if(l.empty())
+ {
+ errorReporter()->error("unknown type `" + type + "'");
+ }
+
+ return l.front();
+}
+
+//
+// SetDescriptor
+//
+Transform::SetDescriptor::SetDescriptor(const DescriptorPtr& parent, int line, const string& target, const string& key,
+ const string& value, const string& type, bool convert) :
+ Descriptor(parent, line), _keyStr(key), _valueStr(value), _type(type), _convert(convert)
+{
+ DescriptorErrorContext ctx(errorReporter(), "set", _line);
+
+ NodePtr node = parse(target);
+ _target = IdentNodePtr::dynamicCast(node);
+ if(!_target)
+ {
+ errorReporter()->error("`target' attribute is not an identifier: `" + target + "'");
+ }
+
+ if(!key.empty())
+ {
+ _key = parse(key);
+ }
+
+ if(!value.empty())
+ {
+ _value = parse(value);
+ }
+}
+
+void
+Transform::SetDescriptor::addChild(const DescriptorPtr&)
+{
+ DescriptorErrorContext ctx(errorReporter(), "set", _line);
+ errorReporter()->error("<set> cannot have child elements");
+}
+
+void
+Transform::SetDescriptor::validate()
+{
+}
+
+void
+Transform::SetDescriptor::execute(TransformSymbolTable& sym, DataInterceptor& interceptor)
+{
+ DescriptorErrorContext ctx(errorReporter(), "set", _line);
+
+ DataPtr data = sym.getValue(_target->getValue());
+ if(data->readOnly())
+ {
+ ostringstream ostr;
+ ostr << _target->getValue();
+ errorReporter()->error("target `" + ostr.str() + "' cannot be modified");
+ }
+
+ DataPtr key;
+ if(_key)
+ {
+ try
+ {
+ key = _key->evaluate(sym);
+ }
+ catch(const EvaluateException& ex)
+ {
+ errorReporter()->error("evaluation of key `" + _keyStr + "' failed:\n" + ex.reason());
+ }
+ }
+
+ DataPtr value;
+ if(_value)
+ {
+ try
+ {
+ value = _value->evaluate(sym);
+ }
+ catch(const EvaluateException& ex)
+ {
+ errorReporter()->error("evaluation of value `" + _valueStr + "' failed:\n" + ex.reason());
+ }
+ }
+
+ Destroyer<DataPtr> valueDestroyer;
+ if(!_type.empty())
+ {
+ assert(!value);
+ Slice::TypeList l = newUnit()->lookupType(_type, false);
+ if(l.empty())
+ {
+ errorReporter()->error("type `" + _type + "' not found");
+ }
+ value = factory()->create(l.front(), false);
+ valueDestroyer.set(value);
+ ObjectRefPtr ref = ObjectRefPtr::dynamicCast(value);
+ if(!ref)
+ {
+ errorReporter()->error("type `" + _type + "' is not a class");
+ }
+ ref->instantiate();
+ }
+
+ if(_key)
+ {
+ DictionaryDataPtr dict = DictionaryDataPtr::dynamicCast(data);
+ if(!dict)
+ {
+ ostringstream ostr;
+ ostr << _target->getValue();
+ errorReporter()->error("target `" + ostr.str() + "' is not a dictionary");
+ }
+ dict->put(key, value, interceptor, _convert);
+ }
+ else
+ {
+ data->set(value, interceptor, _convert);
+ }
+}
+
+//
+// RemoveDescriptor
+//
+Transform::RemoveDescriptor::RemoveDescriptor(const DescriptorPtr& parent, int line, const string& target,
+ const string& key) :
+ Descriptor(parent, line), _keyStr(key)
+{
+ DescriptorErrorContext ctx(errorReporter(), "remove", _line);
+
+ NodePtr node = parse(target);
+ _target = IdentNodePtr::dynamicCast(node);
+ if(!_target)
+ {
+ errorReporter()->error("`target' attribute is not an identifier: `" + target + "'");
+ }
+
+ _key = parse(key);
+}
+
+void
+Transform::RemoveDescriptor::addChild(const DescriptorPtr&)
+{
+ DescriptorErrorContext ctx(errorReporter(), "remove", _line);
+ errorReporter()->error("<remove> cannot have child elements");
+}
+
+void
+Transform::RemoveDescriptor::validate()
+{
+}
+
+void
+Transform::RemoveDescriptor::execute(TransformSymbolTable& sym, DataInterceptor& interceptor)
+{
+ DescriptorErrorContext ctx(errorReporter(), "remove", _line);
+
+ DataPtr key;
+ try
+ {
+ key = _key->evaluate(sym);
+ }
+ catch(const EvaluateException& ex)
+ {
+ errorReporter()->error("evaluation of key `" + _keyStr + "' failed:\n" + ex.reason());
+ }
+
+ DataPtr data = sym.getValue(_target->getValue());
+ if(data->readOnly())
+ {
+ ostringstream ostr;
+ ostr << _target->getValue();
+ errorReporter()->error("target `" + ostr.str() + "' cannot be modified");
+ }
+
+ DictionaryDataPtr dict = DictionaryDataPtr::dynamicCast(data);
+ if(!dict)
+ {
+ ostringstream ostr;
+ ostr << _target->getValue();
+ errorReporter()->error("target `" + ostr.str() + "' is not a dictionary");
+ }
+ dict->remove(key);
+}
+
+//
+// DeleteDescriptor
+//
+Transform::DeleteDescriptor::DeleteDescriptor(const DescriptorPtr& parent, int line) :
+ Descriptor(parent, line)
+{
+}
+
+void
+Transform::DeleteDescriptor::addChild(const DescriptorPtr&)
+{
+ DescriptorErrorContext ctx(errorReporter(), "delete", _line);
+ errorReporter()->error("<delete> cannot have child elements");
+}
+
+void
+Transform::DeleteDescriptor::validate()
+{
+}
+
+void
+Transform::DeleteDescriptor::execute(TransformSymbolTable&, DataInterceptor&)
+{
+ throw DeleteRecordException();
+}
+
+//
+// FailDescriptor
+//
+Transform::FailDescriptor::FailDescriptor(const DescriptorPtr& parent, int line, const string& message) :
+ Descriptor(parent, line), _message(message)
+{
+}
+
+void
+Transform::FailDescriptor::addChild(const DescriptorPtr&)
+{
+ DescriptorErrorContext ctx(errorReporter(), "fail", _line);
+ errorReporter()->error("<fail> cannot have child elements");
+}
+
+void
+Transform::FailDescriptor::validate()
+{
+}
+
+void
+Transform::FailDescriptor::execute(TransformSymbolTable&, DataInterceptor&)
+{
+ throw TransformException(__FILE__, __LINE__, _message);
+}
+
+//
+// EchoDescriptor
+//
+Transform::EchoDescriptor::EchoDescriptor(const DescriptorPtr& parent, int line, const string& message,
+ const string& value) :
+ Descriptor(parent, line), _message(message), _value(value)
+{
+ if(!value.empty())
+ {
+ _node = parse(value);
+ }
+}
+
+void
+Transform::EchoDescriptor::addChild(const DescriptorPtr&)
+{
+ DescriptorErrorContext ctx(errorReporter(), "echo", _line);
+ errorReporter()->error("<echo> cannot have child elements");
+}
+
+void
+Transform::EchoDescriptor::validate()
+{
+}
+
+void
+Transform::EchoDescriptor::execute(TransformSymbolTable& sym, DataInterceptor&)
+{
+ DescriptorErrorContext ctx(errorReporter(), "echo", _line);
+
+ ostream& out = errorReporter()->stream();
+
+ if(!_message.empty())
+ {
+ out << _message;
+ }
+
+ if(_node)
+ {
+ try
+ {
+ DataPtr v = _node->evaluate(sym);
+ v->print(out);
+ }
+ catch(const EvaluateException& ex)
+ {
+ errorReporter()->error("evaluation of value `" + _value + "' failed:\n" + ex.reason());
+ }
+ }
+
+ out << endl;
+}
+
+//
+// ExecutableContainerDescriptor
+//
+Transform::ExecutableContainerDescriptor::ExecutableContainerDescriptor(const DescriptorPtr& parent, int line,
+ const string& name) :
+ Descriptor(parent, line), _name(name)
+{
+}
+
+void
+Transform::ExecutableContainerDescriptor::addChild(const DescriptorPtr& child)
+{
+ _children.push_back(child);
+}
+
+void
+Transform::ExecutableContainerDescriptor::validate()
+{
+ for(vector<DescriptorPtr>::iterator p = _children.begin(); p != _children.end(); ++p)
+ {
+ (*p)->validate();
+ }
+}
+
+void
+Transform::ExecutableContainerDescriptor::execute(TransformSymbolTable& sym, DataInterceptor& interceptor)
+{
+ for(vector<DescriptorPtr>::iterator p = _children.begin(); p != _children.end(); ++p)
+ {
+ (*p)->execute(sym, interceptor);
+ }
+}
+
+//
+// ConditionalDescriptor
+//
+Transform::ConditionalDescriptor::ConditionalDescriptor(const DescriptorPtr& parent, int line, const string& test) :
+ ExecutableContainerDescriptor(parent, line, "if"), Descriptor(parent, line), _test(test)
+{
+ DescriptorErrorContext ctx(errorReporter(), "if", _line);
+ _node = parse(test);
+}
+
+void
+Transform::ConditionalDescriptor::execute(TransformSymbolTable& sym, DataInterceptor& interceptor)
+{
+ DescriptorErrorContext ctx(errorReporter(), "if", _line);
+
+ try
+ {
+ DataPtr b = _node->evaluate(sym);
+ BooleanDataPtr bd = BooleanDataPtr::dynamicCast(b);
+ if(!bd)
+ {
+ errorReporter()->error("expression `" + _test + "' does not evaluate to a boolean");
+ }
+ if(bd->booleanValue())
+ {
+ ExecutableContainerDescriptor::execute(sym, interceptor);
+ }
+ }
+ catch(const EvaluateException& ex)
+ {
+ errorReporter()->error("evaluation of conditional expression `" + _test + "' failed:\n" + ex.reason());
+ }
+}
+
+//
+// IterateDescriptor
+//
+Transform::IterateDescriptor::IterateDescriptor(const DescriptorPtr& parent, int line, const string& target,
+ const string& key, const string& value, const string& element,
+ const string& index) :
+ ExecutableContainerDescriptor(parent, line, "iterate"), Descriptor(parent, line), _key(key), _value(value),
+ _element(element), _index(index)
+{
+ DescriptorErrorContext ctx(errorReporter(), "iterate", _line);
+
+ NodePtr node = parse(target);
+ _target = IdentNodePtr::dynamicCast(node);
+ if(!_target)
+ {
+ errorReporter()->error("`target' attribute is not an identifier: `" + target + "'");
+ }
+}
+
+void
+Transform::IterateDescriptor::execute(TransformSymbolTable& sym, DataInterceptor& interceptor)
+{
+ DescriptorErrorContext ctx(errorReporter(), "iterate", _line);
+
+ DataPtr data = sym.getValue(_target->getValue());
+
+ DictionaryDataPtr dict = DictionaryDataPtr::dynamicCast(data);
+ SequenceDataPtr seq = SequenceDataPtr::dynamicCast(data);
+ if(!dict && !seq)
+ {
+ ostringstream ostr;
+ ostr << _target->getValue();
+ errorReporter()->error("target `" + ostr.str() + "' is not a dictionary or sequence");
+ }
+
+ if(dict)
+ {
+ if(!_element.empty())
+ {
+ errorReporter()->error("attribute `element' specified for dictionary target");
+ }
+ if(!_index.empty())
+ {
+ errorReporter()->error("attribute `index' specified for dictionary target");
+ }
+
+ string key = _key;
+ if(key.empty())
+ {
+ key = "key";
+ }
+
+ string value = _value;
+ if(value.empty())
+ {
+ value = "value";
+ }
+
+ DataMap map = dict->getElements();
+ for(DataMap::iterator p = map.begin(); p != map.end(); ++p)
+ {
+ TransformSymbolTable elemSym(factory(), oldUnit(), newUnit(), errorReporter(), &sym);
+ elemSym.add(key, p->first);
+ elemSym.add(value, p->second);
+ ExecutableContainerDescriptor::execute(elemSym, interceptor);
+ }
+ }
+ else
+ {
+ if(!_key.empty())
+ {
+ errorReporter()->error("attribute `key' specified for sequence target");
+ }
+ if(!_value.empty())
+ {
+ errorReporter()->error("attribute `value' specified for sequence target");
+ }
+
+ string element = _element;
+ if(element.empty())
+ {
+ element = "elem";
+ }
+
+ string index = _index;
+ if(index.empty())
+ {
+ index = "i";
+ }
+
+ DataList l = seq->getElements();
+ Ice::Long i = 0;
+ for(DataList::iterator p = l.begin(); p != l.end(); ++p, ++i)
+ {
+ TransformSymbolTable elemSym(factory(), oldUnit(), newUnit(), errorReporter(), &sym);
+ elemSym.add(element, *p);
+ elemSym.add(index, factory()->createInteger(i, true));
+ ExecutableContainerDescriptor::execute(elemSym, interceptor);
+ }
+ }
+}
+
+//
+// TransformDescriptor
+//
+Transform::TransformDescriptor::TransformDescriptor(const DescriptorPtr& parent, int line, const string& type,
+ bool def) :
+ ExecutableContainerDescriptor(parent, line, "transform"), Descriptor(parent, line), _default(def)
+{
+ DescriptorErrorContext ctx(errorReporter(), "transform", _line);
+
+ Slice::TypeList l;
+
+ l = oldUnit()->lookupType(type, false);
+ if(!l.empty())
+ {
+ _oldType = l.front();
+ }
+
+ l = newUnit()->lookupType(type, false);
+ if(l.empty())
+ {
+ errorReporter()->error("unable to find type `" + type + "' in new Slice definitions");
+ }
+ else
+ {
+ _newType = l.front();
+ }
+}
+
+string
+Transform::TransformDescriptor::type() const
+{
+ return typeName(_newType);
+}
+
+bool
+Transform::TransformDescriptor::doDefaultTransform() const
+{
+ return _default;
+}
+
+//
+// InitDescriptor
+//
+Transform::InitDescriptor::InitDescriptor(const DescriptorPtr& parent, int line, const string& type) :
+ ExecutableContainerDescriptor(parent, line, "init"), Descriptor(parent, line)
+{
+ DescriptorErrorContext ctx(errorReporter(), "init", _line);
+
+ Slice::TypeList l = newUnit()->lookupType(type, false);
+ if(l.empty())
+ {
+ errorReporter()->error("unable to find type `" + type + "' in new Slice definitions");
+ }
+ else
+ {
+ _type = l.front();
+ }
+}
+
+void
+Transform::InitDescriptor::initialize(const DataFactoryPtr& factory, const DataPtr& data,
+ const Ice::CommunicatorPtr& communicator)
+{
+ DescriptorErrorContext ctx(errorReporter(), "init", _line);
+
+#if 0 // TODO
+ // Is interceptor really necessary?
+ TransformSymbolTable sym(factory, _old, _new);
+ sym.add("value", data);
+ eh->raise(true);
+ execute(sym, interceptor);
+#endif
+}
+
+string
+Transform::InitDescriptor::type() const
+{
+ return typeName(_type);
+}
+
+//
+// RecordDescriptor
+//
+Transform::RecordDescriptor::RecordDescriptor(const DescriptorPtr& parent, int line) :
+ ExecutableContainerDescriptor(parent, line, "record"), Descriptor(parent, line)
+{
+}
+
+//
+// DatabaseDescriptor
+//
+Transform::DatabaseDescriptor::DatabaseDescriptor(const DescriptorPtr& parent, int line, const string& keyTypes,
+ const string& valueTypes) :
+ Descriptor(parent, line)
+{
+ DescriptorErrorContext ctx(errorReporter(), "database", _line);
+
+ string oldKeyName, newKeyName;
+ string oldValueName, newValueName;
+ string::size_type pos;
+
+ pos = keyTypes.find(',');
+ if(pos == 0 || pos == keyTypes.size())
+ {
+ errorReporter()->error("invalid key type specification `" + keyTypes +"'");
+ }
+ if(pos == string::npos)
+ {
+ oldKeyName = keyTypes;
+ newKeyName = keyTypes;
+ }
+ else
+ {
+ oldKeyName = keyTypes.substr(0, pos);
+ newKeyName = keyTypes.substr(pos + 1);
+ }
+
+ pos = valueTypes.find(',');
+ if(pos == 0 || pos == valueTypes.size())
+ {
+ errorReporter()->error("invalid value type specification `" + valueTypes +"'");
+ }
+ if(pos == string::npos)
+ {
+ oldValueName = valueTypes;
+ newValueName = valueTypes;
+ }
+ else
+ {
+ oldValueName = valueTypes.substr(0, pos);
+ newValueName = valueTypes.substr(pos + 1);
+ }
+
+ //
+ // Look up the Slice definitions for the key and value types.
+ //
+ _oldKey = findType(oldUnit(), oldKeyName);
+ _newKey = findType(newUnit(), newKeyName);
+ _oldValue = findType(oldUnit(), oldValueName);
+ _newValue = findType(newUnit(), newValueName);
+}
+
+void
+Transform::DatabaseDescriptor::addChild(const DescriptorPtr& child)
+{
+ DescriptorErrorContext ctx(errorReporter(), "database", _line);
+
+ RecordDescriptorPtr rec = RecordDescriptorPtr::dynamicCast(child);
+ if(!rec)
+ {
+ errorReporter()->error("invalid child for <database> descriptor");
+ }
+ if(_record)
+ {
+ errorReporter()->error("only one <record> element can be specified");
+ }
+ _record = rec;
+}
+
+void
+Transform::DatabaseDescriptor::validate()
+{
+ if(!_record)
+ {
+ _record = new RecordDescriptor(this, _line);
+ }
+ _record->validate();
+}
+
+void
+Transform::DatabaseDescriptor::execute(TransformSymbolTable&, DataInterceptor&)
+{
+ assert(false);
+}
+
+bool
+Transform::DatabaseDescriptor::transform(IceInternal::BasicStream& inKey, IceInternal::BasicStream& inValue,
+ IceInternal::BasicStream& outKey, IceInternal::BasicStream& outValue,
+ const TransformMap& transforms)
+{
+ errorReporter()->raise(false);
+
+ TransformInterceptor interceptor(factory(), errorReporter(), oldUnit(), newUnit(), transforms);
+
+ //
+ // Create data representations of the old key and value types.
+ //
+ factory()->disableInitializers();
+ DataPtr oldKeyData = factory()->create(_oldKey, true);
+ Destroyer<DataPtr> oldKeyDataDestroyer(oldKeyData);
+ DataPtr oldValueData = factory()->create(_oldValue, true);
+ Destroyer<DataPtr> oldValueDataDestroyer(oldValueData);
+
+ //
+ // Unmarshal the old key and value.
+ //
+ oldKeyData->unmarshal(inKey);
+ oldValueData->unmarshal(inValue);
+ if(_oldValue->usesClasses())
+ {
+ inValue.readPendingObjects();
+ oldValueData->registerObjects(interceptor.getObjectMap());
+ }
+ factory()->enableInitializers();
+
+ //
+ // Create data representations of the new key and value types.
+ //
+ DataPtr newKeyData = factory()->create(_newKey, false);
+ Destroyer<DataPtr> newKeyDataDestroyer(newKeyData);
+ DataPtr newValueData = factory()->create(_newValue, false);
+ Destroyer<DataPtr> newValueDataDestroyer(newValueData);
+
+ //
+ // Copy the data from the old key and value to the new key and value, if possible.
+ //
+ newKeyData->transform(oldKeyData, interceptor);
+ newValueData->transform(oldValueData, interceptor);
+
+ //
+ // Execute the <record> descriptor.
+ //
+ // TODO: Revisit identifiers.
+ //
+ TransformSymbolTable sym(factory(), oldUnit(), newUnit(), errorReporter());
+ sym.add("oldkey", oldKeyData);
+ sym.add("newkey", newKeyData);
+ sym.add("oldvalue", oldValueData);
+ sym.add("newvalue", newValueData);
+ errorReporter()->raise(true);
+ _record->execute(sym, interceptor);
+
+ newKeyData->marshal(outKey);
+ newValueData->marshal(outValue);
+ if(_newValue->usesClasses())
+ {
+ outValue.writePendingObjects();
+ }
+
+ return true;
+}
+
+//
+// TransformerDescriptor
+//
+Transform::TransformerDescriptor::TransformerDescriptor(const DataFactoryPtr& factory, const Slice::UnitPtr& oldUnit,
+ const Slice::UnitPtr& newUnit,
+ const ErrorReporterPtr& errorReporter, int line) :
+ Descriptor(0, line), _factory(factory), _old(oldUnit), _new(newUnit), _errorReporter(errorReporter)
+{
+}
+
+void
+Transform::TransformerDescriptor::addChild(const DescriptorPtr& child)
+{
+ DescriptorErrorContext ctx(errorReporter(), "transformer", _line);
+
+ DatabaseDescriptorPtr db = DatabaseDescriptorPtr::dynamicCast(child);
+ TransformDescriptorPtr transform = TransformDescriptorPtr::dynamicCast(child);
+ InitDescriptorPtr init = InitDescriptorPtr::dynamicCast(child);
+
+ if(db)
+ {
+ if(_database)
+ {
+ errorReporter()->error("only one <database> element can be specified");
+ }
+ else
+ {
+ _database = db;
+ _children.push_back(db);
+ }
+ }
+ else if(transform)
+ {
+ string name = transform->type();
+ TransformMap::iterator p = _transforms.find(name);
+ if(p != _transforms.end())
+ {
+ errorReporter()->error("transform `" + name + "' specified more than once");
+ }
+ _transforms.insert(TransformMap::value_type(name, transform));
+ _children.push_back(transform);
+ }
+ else if(init)
+ {
+ string name = init->type();
+ _factory->addInitializer(init->type(), init);
+ _children.push_back(init);
+ }
+ else
+ {
+ errorReporter()->error("invalid child element");
+ }
+}
+
+void
+Transform::TransformerDescriptor::validate()
+{
+ DescriptorErrorContext ctx(errorReporter(), "transformer", _line);
+
+ if(!_database)
+ {
+ errorReporter()->error("no <database> element specified");
+ }
+
+ for(vector<DescriptorPtr>::iterator p = _children.begin(); p != _children.end(); ++p)
+ {
+ (*p)->validate();
+ }
+}
+
+void
+Transform::TransformerDescriptor::execute(TransformSymbolTable&, DataInterceptor&)
+{
+ assert(false);
+}
+
+Transform::DataFactoryPtr
+Transform::TransformerDescriptor::factory() const
+{
+ return _factory;
+}
+
+Slice::UnitPtr
+Transform::TransformerDescriptor::oldUnit() const
+{
+ return _old;
+}
+
+Slice::UnitPtr
+Transform::TransformerDescriptor::newUnit() const
+{
+ return _new;
+}
+
+Transform::ErrorReporterPtr
+Transform::TransformerDescriptor::errorReporter() const
+{
+ return _errorReporter;
+}
+
+void
+Transform::TransformerDescriptor::transform(const Ice::CommunicatorPtr& communicator, Db* db, Db* dbNew)
+{
+ DescriptorErrorContext ctx(errorReporter(), "transformer", _line);
+
+ Dbc* dbc = 0;
+
+ IceInternal::InstancePtr instance = IceInternal::getInstance(communicator);
+ db->cursor(0, &dbc, 0);
+
+ communicator->addObjectFactory(new Transform::ObjectFactory(_factory, _old), "");
+
+ try
+ {
+ Dbt dbKey, dbValue;
+ while(dbc->get(&dbKey, &dbValue, DB_NEXT) == 0)
+ {
+ IceInternal::BasicStream inKey(instance.get());
+ inKey.b.resize(dbKey.get_size());
+ memcpy(&inKey.b[0], dbKey.get_data(), dbKey.get_size());
+ inKey.i = inKey.b.begin();
+
+ IceInternal::BasicStream inValue(instance.get());
+ inValue.b.resize(dbValue.get_size());
+ memcpy(&inValue.b[0], dbValue.get_data(), dbValue.get_size());
+ inValue.i = inValue.b.begin();
+ inValue.startReadEncaps();
+
+ IceInternal::BasicStream outKey(instance.get());
+ IceInternal::BasicStream outValue(instance.get());
+ outValue.startWriteEncaps();
+ try
+ {
+ if(_database->transform(inKey, inValue, outKey, outValue, _transforms))
+ {
+ outValue.endWriteEncaps();
+ Dbt dbNewKey(&outKey.b[0], outKey.b.size()), dbNewValue(&outValue.b[0], outValue.b.size());
+ if(dbNew->put(0, &dbNewKey, &dbNewValue, DB_NOOVERWRITE) == DB_KEYEXIST)
+ {
+ errorReporter()->error("duplicate key encountered");
+ }
+ }
+ }
+ catch(const DeleteRecordException&)
+ {
+ // The record is deleted simply by not adding it to the new database.
+ }
+ }
+ }
+ catch(...)
+ {
+ if(dbc)
+ {
+ dbc->close();
+ }
+ communicator->removeObjectFactory("");
+ throw;
+ }
+
+ communicator->removeObjectFactory("");
+
+ if(dbc)
+ {
+ dbc->close();
+ }
+}
+
+//
+// DescriptorHandler
+//
+Transform::DescriptorHandler::DescriptorHandler(const DataFactoryPtr& factory, const Slice::UnitPtr& oldUnit,
+ const Slice::UnitPtr& newUnit, const ErrorReporterPtr& errorReporter) :
+ _factory(factory), _old(oldUnit), _new(newUnit), _errorReporter(errorReporter)
+{
+}
+
+void
+Transform::DescriptorHandler::startElement(const string& name, const IceXML::Attributes& attributes, int line,
+ int column)
+{
+ DescriptorPtr d;
+
+ if(name == "transformer")
+ {
+ if(_current)
+ {
+ _errorReporter->descriptorError("<transformer> must be the top-level element", line);
+ }
+
+ _transformer = new TransformerDescriptor(_factory, _old, _new, _errorReporter, line);
+ d = _transformer;
+ }
+ else if(name == "database")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<database> must be a child of <transformer>", line);
+ }
+
+ IceXML::Attributes::const_iterator p = attributes.find("key");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `key' is missing from <database>", line);
+ }
+ string keyTypes = p->second;
+
+ p = attributes.find("value");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `value' is missing from <database>", line);
+ }
+ string valueTypes = p->second;
+
+ d = new DatabaseDescriptor(_current, line, keyTypes, valueTypes);
+ }
+ else if(name == "record")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<record> must be a child of <database>", line);
+ }
+
+ d = new RecordDescriptor(_current, line);
+ }
+ else if(name == "transform")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<transform> must be a child of <transformer>", line);
+ }
+
+ IceXML::Attributes::const_iterator p;
+
+ string type;
+ p = attributes.find("type");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `type' is missing from <transform>", line);
+ }
+ type = p->second;
+
+ bool def = true;
+ p = attributes.find("default");
+ if(p != attributes.end())
+ {
+ if(p->second == "false")
+ {
+ def = false;
+ }
+ }
+
+ d = new TransformDescriptor(_current, line, type, def);
+ }
+ else if(name == "init")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<init> must be a child of <transformer>", line);
+ }
+
+ IceXML::Attributes::const_iterator p = attributes.find("type");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `type' is missing from <init>", line);
+ }
+
+ d = new InitDescriptor(_current, line, p->second);
+ }
+ else if(name == "set")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<set> cannot be a top-level element", line);
+ }
+
+ IceXML::Attributes::const_iterator p;
+
+ string target, key, value, type;
+ bool convert = false;
+ p = attributes.find("target");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `target' is missing from <set>", line);
+ }
+ target = p->second;
+
+ p = attributes.find("key");
+ if(p != attributes.end())
+ {
+ key = p->second;
+ }
+
+ p = attributes.find("value");
+ if(p != attributes.end())
+ {
+ value = p->second;
+ }
+
+ p = attributes.find("type");
+ if(p != attributes.end())
+ {
+ type = p->second;
+ }
+
+ p = attributes.find("convert");
+ if(p != attributes.end())
+ {
+ convert = p->second == "true";
+ }
+
+ if((value.empty() && type.empty()) || (!value.empty() && !type.empty()))
+ {
+ _errorReporter->descriptorError("<set> requires one of the attributes `value' or 'type'", line);
+ }
+
+ d = new SetDescriptor(_current, line, target, key, value, type, convert);
+ }
+ else if(name == "remove")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<remove> cannot be a top-level element", line);
+ }
+
+ IceXML::Attributes::const_iterator p;
+
+ string target, key;
+ p = attributes.find("target");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `target' is missing from <remove>", line);
+ }
+ target = p->second;
+
+ p = attributes.find("key");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `key' is missing from <remove>", line);
+ }
+ key = p->second;
+
+ d = new RemoveDescriptor(_current, line, target, key);
+ }
+ else if(name == "delete")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<delete> cannot be a top-level element", line);
+ }
+
+ d = new DeleteDescriptor(_current, line);
+ }
+ else if(name == "fail")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<fail> cannot be a top-level element", line);
+ }
+
+ IceXML::Attributes::const_iterator p = attributes.find("message");
+ string message;
+ if(p != attributes.end())
+ {
+ message = p->second;
+ }
+
+ d = new FailDescriptor(_current, line, message);
+ }
+ else if(name == "echo")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<echo> cannot be a top-level element", line);
+ }
+
+ IceXML::Attributes::const_iterator p;
+ string message, value;
+
+ p = attributes.find("message");
+ if(p != attributes.end())
+ {
+ message = p->second;
+ }
+
+ p = attributes.find("value");
+ if(p != attributes.end())
+ {
+ value = p->second;
+ }
+
+ d = new EchoDescriptor(_current, line, message, value);
+ }
+ else if(name == "if")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<if> cannot be a top-level element", line);
+ }
+
+ IceXML::Attributes::const_iterator p = attributes.find("test");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `test' is missing from <if>", line);
+ }
+
+ d = new ConditionalDescriptor(_current, line, p->second);
+ }
+ else if(name == "iterate")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<iterate> cannot be a top-level element", line);
+ }
+
+ IceXML::Attributes::const_iterator p;
+ string target, key, value, element, index;
+
+ p = attributes.find("target");
+ if(p == attributes.end())
+ {
+ _errorReporter->descriptorError("required attribute `target' is missing from <iterate>", line);
+ }
+ target = p->second;
+
+ p = attributes.find("key");
+ if(p != attributes.end())
+ {
+ key = p->second;
+ }
+
+ p = attributes.find("value");
+ if(p != attributes.end())
+ {
+ value = p->second;
+ }
+
+ p = attributes.find("element");
+ if(p != attributes.end())
+ {
+ element = p->second;
+ }
+
+ p = attributes.find("index");
+ if(p != attributes.end())
+ {
+ index = p->second;
+ }
+
+ d = new IterateDescriptor(_current, line, target, key, value, element, index);
+ }
+ else
+ {
+ _errorReporter->descriptorError("unknown descriptor `" + name + "'", line);
+ }
+
+ if(_current)
+ {
+ _current->addChild(d);
+ }
+ _current = d;
+}
+
+void
+Transform::DescriptorHandler::endElement(const std::string& name, int, int)
+{
+ assert(_current);
+ _current = _current->parent();
+}
+
+void
+Transform::DescriptorHandler::characters(const std::string&, int, int)
+{
+}
+
+void
+Transform::DescriptorHandler::error(const std::string& msg, int line, int col)
+{
+ _errorReporter->descriptorError(msg, line);
+}
+
+Transform::TransformerDescriptorPtr
+Transform::DescriptorHandler::descriptor() const
+{
+ return _transformer;
+}
+
+//
+// TransformInterceptor
+//
+Transform::TransformInterceptor::TransformInterceptor(const DataFactoryPtr& factory,
+ const ErrorReporterPtr& errorReporter,
+ const Slice::UnitPtr& oldUnit,
+ const Slice::UnitPtr& newUnit,
+ const TransformMap& transformMap) :
+ _factory(factory), _errorReporter(errorReporter), _old(oldUnit), _new(newUnit), _transformMap(transformMap)
+{
+}
+
+bool
+Transform::TransformInterceptor::preTransform(const DataPtr& dest, const DataPtr&)
+{
+ //
+ // Allow a transform descriptor to disable the default transformation.
+ //
+ string type = typeName(dest->getType());
+ TransformMap::const_iterator p = _transformMap.find(type);
+ if(p != _transformMap.end())
+ {
+ return p->second->doDefaultTransform();
+ }
+
+ return true;
+}
+
+void
+Transform::TransformInterceptor::postTransform(const DataPtr& dest, const DataPtr& src)
+{
+ //
+ // Execute the type's transform (if any).
+ //
+ string type = typeName(dest->getType());
+ TransformMap::const_iterator p = _transformMap.find(type);
+ if(p != _transformMap.end())
+ {
+ bool raise = _errorReporter->raise();
+ _errorReporter->raise(true);
+ TransformSymbolTable sym(_factory, _old, _new, _errorReporter);
+ sym.add("new", dest);
+ sym.add("old", src);
+ try
+ {
+ p->second->execute(sym, *this);
+ _errorReporter->raise(raise);
+ }
+ catch(...)
+ {
+ _errorReporter->raise(raise);
+ throw;
+ }
+ }
+}
+
+Transform::ObjectDataMap&
+Transform::TransformInterceptor::getObjectMap()
+{
+ return _objectMap;
+}
+
+//
+// Transformer
+//
+Transform::Transformer::Transformer(const Ice::CommunicatorPtr& communicator, const Slice::UnitPtr& oldUnit,
+ const Slice::UnitPtr& newUnit, bool ignoreTypeChanges) :
+ _communicator(communicator), _old(oldUnit), _new(newUnit), _ignoreTypeChanges(ignoreTypeChanges)
+{
+}
+
+void
+Transform::Transformer::analyze(const string& oldKey, const string& newKey, const string& oldValue,
+ const string& newValue, ostream& descriptors, Ice::StringSeq& missingTypes,
+ Ice::StringSeq& errors)
+{
+ //
+ // Look up the Slice definitions for the key and value types.
+ //
+ Slice::TypePtr oldKeyType = findType(_old, oldKey, errors);
+ Slice::TypePtr newKeyType = findType(_new, newKey, errors);
+ Slice::TypePtr oldValueType = findType(_old, oldValue, errors);
+ Slice::TypePtr newValueType = findType(_new, newValue, errors);
+ if(!oldKeyType || !newKeyType || !oldValueType || !newValueType)
+ {
+ return;
+ }
+
+ Analyzer analyzer(_old, _new, _ignoreTypeChanges);
+ analyzer.analyze(oldKeyType, newKeyType, oldValueType, newValueType, descriptors, missingTypes, errors);
+}
+
+void
+Transform::Transformer::analyze(ostream& descriptors, Ice::StringSeq& missingTypes, Ice::StringSeq& errors)
+{
+ createEvictorSliceTypes(_old);
+ createEvictorSliceTypes(_new);
+
+ const string keyType = "::Freeze::EvictorStorageKey";
+ const string valueType = "::Freeze::ObjectRecord";
+ analyze(keyType, keyType, valueType, valueType, descriptors, missingTypes, errors);
+}
+
+void
+Transform::Transformer::transform(istream& is, Db* db, Db* dbNew, ostream& errors)
+{
+ createCoreSliceTypes(_old);
+ createCoreSliceTypes(_new);
+
+ ErrorReporterPtr errorReporter = new ErrorReporter(errors);
+
+ try
+ {
+ DataFactoryPtr factory = new DataFactory(_communicator, _new, errorReporter);
+ DescriptorHandler dh(factory, _old, _new, errorReporter);
+ IceXML::Parser::parse(is, dh);
+
+ TransformerDescriptorPtr descriptor = dh.descriptor();
+ descriptor->validate();
+ descriptor->transform(_communicator, db, dbNew);
+ }
+ catch(const IceXML::ParserException& ex)
+ {
+ errorReporter->error(ex.reason());
+ }
+}
+
+void
+Transform::Transformer::createCoreSliceTypes(const Slice::UnitPtr& unit)
+{
+ string scoped;
+ Slice::TypeList l;
+ Slice::ContainedList c;
+
+ //
+ // Create the Slice definition for _FacetMap if it doesn't exist. This type is
+ // necessary for marshaling an object's facet map.
+ //
+ l = unit->lookupTypeNoBuiltin("::_FacetMap", false);
+ if(l.empty())
+ {
+ Slice::TypePtr str = unit->builtin(Slice::Builtin::KindString);
+ Slice::TypePtr obj = unit->builtin(Slice::Builtin::KindObject);
+ unit->createDictionary("_FacetMap", str, obj, false);
+ }
+ else
+ {
+ assert(Slice::DictionaryPtr::dynamicCast(l.front()));
+ }
+}
+
+void
+Transform::Transformer::createEvictorSliceTypes(const Slice::UnitPtr& unit)
+{
+ string scoped;
+ Slice::TypeList l;
+ Slice::ContainedList c;
+
+ //
+ // Create the Ice module if necessary.
+ //
+ c = unit->lookupContained("Ice", false);
+ Slice::ModulePtr ice;
+ if(c.empty())
+ {
+ ice = unit->createModule("Ice");
+ }
+ else
+ {
+ ice = Slice::ModulePtr::dynamicCast(c.front());
+ if(!ice)
+ {
+ throw TransformException(__FILE__, __LINE__,
+ "the symbol `::Ice' is defined in Slice but is not a module");
+ }
+ }
+
+ //
+ // Create the Slice definition for Ice::Identity if it doesn't exist.
+ //
+ scoped = "::Ice::Identity";
+ l = unit->lookupTypeNoBuiltin(scoped, false);
+ Slice::StructPtr identity;
+ if(l.empty())
+ {
+ identity = ice->createStruct("Identity", false);
+ Slice::TypePtr str = unit->builtin(Slice::Builtin::KindString);
+ identity->createDataMember("category", str);
+ identity->createDataMember("name", str);
+ }
+ else
+ {
+ identity = Slice::StructPtr::dynamicCast(l.front());
+ if(!identity)
+ {
+ throw TransformException(__FILE__, __LINE__,
+ "the symbol `::Ice::Identity' is defined in Slice but is not a struct");
+ }
+ }
+
+ //
+ // Create the Slice definition for Ice::FacetPath if it doesn't exist.
+ //
+ scoped = "::Ice::FacetPath";
+ l = unit->lookupTypeNoBuiltin(scoped, false);
+ Slice::SequencePtr facetPath;
+ if(l.empty())
+ {
+ Slice::TypePtr str = unit->builtin(Slice::Builtin::KindString);
+ facetPath = ice->createSequence("FacetPath", str, false);
+ }
+ else
+ {
+ facetPath = Slice::SequencePtr::dynamicCast(l.front());
+ if(!facetPath)
+ {
+ throw TransformException(__FILE__, __LINE__,
+ "the symbol `::Ice::FacetPath' is defined in Slice but is not a sequence");
+ }
+ }
+
+ //
+ // Create the Freeze module if necessary.
+ //
+ c = unit->lookupContained("Freeze", false);
+ Slice::ModulePtr freeze;
+ if(c.empty())
+ {
+ freeze = unit->createModule("Freeze");
+ }
+ else
+ {
+ freeze = Slice::ModulePtr::dynamicCast(c.front());
+ if(!freeze)
+ {
+ throw TransformException(__FILE__, __LINE__,
+ "the symbol `::Freeze' is defined in Slice but is not a module");
+ }
+ }
+
+ //
+ // Create the Slice definition for Freeze::EvictorStorageKey if it doesn't exist.
+ //
+ scoped = "::Freeze::EvictorStorageKey";
+ l = unit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ Slice::StructPtr esk = freeze->createStruct("EvictorStorageKey", false);
+ esk->createDataMember("identity", identity);
+ esk->createDataMember("facet", facetPath);
+ }
+ else
+ {
+ if(!Slice::StructPtr::dynamicCast(l.front()))
+ {
+ throw TransformException(__FILE__, __LINE__, "the symbol `::Freeze::EvictorStorageKey' is defined in "
+ "Slice but is not a struct");
+ }
+ }
+
+ //
+ // Create the Slice definition for Freeze::Statistics if it doesn't exist.
+ //
+ scoped = "::Freeze::Statistics";
+ l = unit->lookupTypeNoBuiltin(scoped, false);
+ Slice::StructPtr stats;
+ if(l.empty())
+ {
+ stats = freeze->createStruct("Statistics", false);
+ Slice::TypePtr tl = unit->builtin(Slice::Builtin::KindLong);
+ stats->createDataMember("creationTime", tl);
+ stats->createDataMember("lastSaveTime", tl);
+ stats->createDataMember("avgSaveTime", tl);
+ }
+ else
+ {
+ stats = Slice::StructPtr::dynamicCast(l.front());
+ if(!stats)
+ {
+ throw TransformException(__FILE__, __LINE__, "the symbol `::Freeze::Statistics' is defined in "
+ "Slice but is not a struct");
+ }
+ }
+
+ //
+ // Create the Slice definition for Freeze::ObjectRecord if it doesn't exist.
+ //
+ scoped = "::Freeze::ObjectRecord";
+ l = unit->lookupTypeNoBuiltin(scoped, false);
+ if(l.empty())
+ {
+ Slice::StructPtr rec = freeze->createStruct("ObjectRecord", false);
+ Slice::TypePtr obj = unit->builtin(Slice::Builtin::KindObject);
+ rec->createDataMember("servant", obj);
+ rec->createDataMember("stats", stats);
+ }
+ else
+ {
+ if(!Slice::StructPtr::dynamicCast(l.front()))
+ {
+ throw TransformException(__FILE__, __LINE__, "the symbol `::Freeze::ObjectRecord' is defined in "
+ "Slice but is not a struct");
+ }
+ }
+}
+
+Slice::TypePtr
+Transform::Transformer::findType(const Slice::UnitPtr& u, const string& type, Ice::StringSeq& errors)
+{
+ Slice::TypeList l;
+
+ l = u->lookupType(type, false);
+ if(l.empty())
+ {
+ errors.push_back("error: unknown type `" + type + "'");
+ return 0;
+ }
+
+ return l.front();
+}