diff options
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/Transform/.depend | 11 | ||||
-rw-r--r-- | cpp/src/Transform/Analyzer.cpp | 1146 | ||||
-rw-r--r-- | cpp/src/Transform/Analyzer.h | 41 | ||||
-rw-r--r-- | cpp/src/Transform/Data.cpp | 3458 | ||||
-rw-r--r-- | cpp/src/Transform/Data.h | 658 | ||||
-rw-r--r-- | cpp/src/Transform/Error.cpp | 192 | ||||
-rw-r--r-- | cpp/src/Transform/Error.h | 75 | ||||
-rw-r--r-- | cpp/src/Transform/Exception.cpp | 60 | ||||
-rw-r--r-- | cpp/src/Transform/Grammar.y | 264 | ||||
-rw-r--r-- | cpp/src/Transform/GrammarUtil.h | 144 | ||||
-rw-r--r-- | cpp/src/Transform/Makefile | 74 | ||||
-rw-r--r-- | cpp/src/Transform/Node.cpp | 464 | ||||
-rw-r--r-- | cpp/src/Transform/Node.h | 166 | ||||
-rw-r--r-- | cpp/src/Transform/Parser.cpp | 75 | ||||
-rw-r--r-- | cpp/src/Transform/Parser.h | 33 | ||||
-rw-r--r-- | cpp/src/Transform/Scanner.l | 375 | ||||
-rw-r--r-- | cpp/src/Transform/TransformDB.cpp | 563 | ||||
-rw-r--r-- | cpp/src/Transform/TransformUtil.cpp | 33 | ||||
-rw-r--r-- | cpp/src/Transform/TransformUtil.h | 52 | ||||
-rw-r--r-- | cpp/src/Transform/Transformer.cpp | 2156 |
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(); +} |