diff options
Diffstat (limited to 'cpp')
31 files changed, 13292 insertions, 0 deletions
diff --git a/cpp/src/FreezeScript/.depend b/cpp/src/FreezeScript/.depend new file mode 100644 index 00000000000..64d33f7b8ad --- /dev/null +++ b/cpp/src/FreezeScript/.depend @@ -0,0 +1,15 @@ +Grammar.o: Grammar.cpp ../FreezeScript/GrammarUtil.h ../FreezeScript/Parser.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h +Scanner.o: Scanner.cpp ../../include/IceUtil/Config.h ../FreezeScript/GrammarUtil.h ../FreezeScript/Parser.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/Grammar.h +AssignVisitor.o: AssignVisitor.cpp ../FreezeScript/AssignVisitor.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/Util.h +Data.o: Data.cpp ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/Util.h ../FreezeScript/Exception.h +Error.o: Error.cpp ../FreezeScript/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 ../FreezeScript/Exception.h ../FreezeScript/Util.h +Functions.o: Functions.cpp ../FreezeScript/Functions.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/Util.h ../../include/IceUtil/UUID.h +Exception.o: Exception.cpp ../FreezeScript/Exception.h ../../include/IceUtil/Exception.h ../../include/IceUtil/Config.h +Parser.o: Parser.cpp ../FreezeScript/Parser.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/GrammarUtil.h +Print.o: Print.cpp ../FreezeScript/Print.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/Util.h ../../include/IceUtil/OutputUtil.h +TransformAnalyzer.o: TransformAnalyzer.cpp ../FreezeScript/TransformAnalyzer.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 ../FreezeScript/Util.h ../../include/IceUtil/OutputUtil.h +TransformDescriptors.o: TransformDescriptors.cpp ../FreezeScript/TransformDescriptors.h ../FreezeScript/Parser.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/TransformVisitor.h ../../include/IceXML/Parser.h ../FreezeScript/AssignVisitor.h ../FreezeScript/Print.h ../FreezeScript/Functions.h ../FreezeScript/Exception.h ../FreezeScript/Util.h ../../include/IceUtil/UUID.h +TransformVisitor.o: TransformVisitor.cpp ../FreezeScript/TransformVisitor.h ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Error.h ../FreezeScript/Util.h +Transformer.o: Transformer.cpp ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Exception.h ../FreezeScript/TransformDescriptors.h ../FreezeScript/Parser.h ../FreezeScript/Data.h ../FreezeScript/Error.h ../FreezeScript/TransformVisitor.h ../../include/IceXML/Parser.h ../FreezeScript/TransformAnalyzer.h ../FreezeScript/Util.h +Util.o: Util.cpp ../FreezeScript/Util.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 ../FreezeScript/Exception.h ../../include/Slice/Preprocessor.h +TransformDB.o: TransformDB.cpp ../FreezeScript/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/IceUtil/GCShared.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 ../FreezeScript/Exception.h ../FreezeScript/Util.h diff --git a/cpp/src/FreezeScript/AssignVisitor.cpp b/cpp/src/FreezeScript/AssignVisitor.cpp new file mode 100644 index 00000000000..1037e6e96a3 --- /dev/null +++ b/cpp/src/FreezeScript/AssignVisitor.cpp @@ -0,0 +1,598 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/AssignVisitor.h> +#include <FreezeScript/Util.h> + +using namespace std; + +FreezeScript::AssignVisitor::AssignVisitor(const DataPtr& src, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, bool convert, + const string& context) : + _src(src), _factory(factory), _errorReporter(errorReporter), _convert(convert), + _context(context) +{ +} + +void +FreezeScript::AssignVisitor::visitBoolean(const BooleanDataPtr& dest) +{ + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + string v = s->getValue(); + if(v == "true") + { + dest->setValue(true); + } + else if(v == "false") + { + dest->setValue(false); + } + else + { + conversionError(dest->getType(), _src->getType(), v); + } + } + else + { + dest->setValue(_src->booleanValue(_convert)); + } +} + +void +FreezeScript::AssignVisitor::visitInteger(const IntegerDataPtr& dest) +{ + dest->setValue(_src->integerValue(_convert), true); +} + +void +FreezeScript::AssignVisitor::visitDouble(const DoubleDataPtr& dest) +{ + dest->setValue(_src->doubleValue(_convert)); +} + +void +FreezeScript::AssignVisitor::visitString(const StringDataPtr& dest) +{ + dest->setValue(_src->stringValue(_convert)); +} + +void +FreezeScript::AssignVisitor::visitProxy(const ProxyDataPtr& dest) +{ + ProxyDataPtr p = ProxyDataPtr::dynamicCast(_src); + if(p) + { + dest->setValue(p->getValue()); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + dest->setValue(s->getValue(), false); + } + else + { + typeMismatchError(dest->getType(), _src->getType()); + } + } +} + +void +FreezeScript::AssignVisitor::visitStruct(const StructDataPtr& dest) +{ + Slice::StructPtr type = Slice::StructPtr::dynamicCast(dest->getType()); + assert(type); + StructDataPtr src = StructDataPtr::dynamicCast(_src); + if(src && isCompatible(type, src->getType())) + { + // + // Assign members with the same name. + // + DataMemberMap srcMap = src->getMembers(); + DataMemberMap destMap = dest->getMembers(); + string typeName = typeToString(type); + for(DataMemberMap::iterator p = destMap.begin(); p != destMap.end(); ++p) + { + DataMemberMap::iterator q = srcMap.find(p->first); + if(q != srcMap.end()) + { + string context = typeName + " member " + p->first + " value"; + AssignVisitor v(q->second, _factory, _errorReporter, _convert, context); + p->second->visit(v); + } + } + } + else + { + typeMismatchError(type, _src->getType()); + } +} + +void +FreezeScript::AssignVisitor::visitSequence(const SequenceDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + SequenceDataPtr src = SequenceDataPtr::dynamicCast(_src); + if(src && isCompatible(type, src->getType())) + { + DataList& srcElements = src->getElements(); + DataList destElements; + Slice::SequencePtr seqType = Slice::SequencePtr::dynamicCast(type); + assert(seqType); + Slice::TypePtr elemType = seqType->type(); + string typeName = typeToString(type); + for(DataList::const_iterator p = srcElements.begin(); p != srcElements.end(); ++p) + { + DataPtr element = _factory->create(elemType, false); + Destroyer<DataPtr> elementDestroyer(element); + AssignVisitor v(*p, _factory, _errorReporter, _convert, typeName + " element"); + element->visit(v); + destElements.push_back(element); + elementDestroyer.release(); + } + DataList& l = dest->getElements(); + l.swap(destElements); + } + else + { + typeMismatchError(type, _src->getType()); + } +} + +void +FreezeScript::AssignVisitor::visitEnum(const EnumDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + IntegerDataPtr i = IntegerDataPtr::dynamicCast(_src); + if(i) + { + if(_convert) + { + if(!dest->setValue(i->integerValue())) + { + rangeError(i->toString(), type); + } + } + else + { + conversionError(type, i->getType(), i->toString()); + } + } + else + { + string name; + EnumDataPtr e = EnumDataPtr::dynamicCast(_src); + if(e && isCompatible(type, _src->getType())) + { + name = e->toString(); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + name = s->getValue(); + } + else + { + typeMismatchError(type, _src->getType()); + } + } + + if(!dest->setValueAsString(name)) + { + conversionError(type, _src->getType(), name); + } + } +} + +void +FreezeScript::AssignVisitor::visitDictionary(const DictionaryDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + DictionaryDataPtr d = DictionaryDataPtr::dynamicCast(_src); + if(d && isCompatible(type, _src->getType())) + { + DataMap& srcMap = d->getElements(); + DataMap destMap; + Slice::DictionaryPtr dictType = Slice::DictionaryPtr::dynamicCast(type); + assert(dictType); + Slice::TypePtr keyType = dictType->keyType(); + Slice::TypePtr valueType = dictType->valueType(); + string typeName = typeToString(type); + for(DataMap::const_iterator p = srcMap.begin(); p != srcMap.end(); ++p) + { + DataPtr key = _factory->create(keyType, false); + Destroyer<DataPtr> keyDestroyer(key); + DataPtr value = _factory->create(valueType, false); + Destroyer<DataPtr> valueDestroyer(value); + + AssignVisitor keyVisitor(p->first, _factory, _errorReporter, _convert, typeName + " key"); + key->visit(keyVisitor); + + AssignVisitor valueVisitor(p->second, _factory, _errorReporter, _convert, typeName + " value"); + value->visit(valueVisitor); + + DataMap::const_iterator q = destMap.find(key); + if(q != destMap.end()) + { + error("duplicate dictionary key in " + typeToString(dictType)); + } + else + { + destMap.insert(DataMap::value_type(key, value)); + keyDestroyer.release(); + valueDestroyer.release(); + } + } + DataMap& m = dest->getElements(); + m.swap(destMap); + } + else + { + typeMismatchError(type, _src->getType()); + } +} + +void +FreezeScript::AssignVisitor::visitObject(const ObjectRefPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + ObjectRefPtr src = ObjectRefPtr::dynamicCast(_src); + if(!src) + { + typeMismatchError(type, _src->getType()); + } + + ObjectDataPtr srcValue = src->getValue(); + Slice::TypePtr srcType = src->getType(); + if(!srcValue) + { + // + // Allow a nil value from type Object. + // + if(Slice::BuiltinPtr::dynamicCast(srcType) || isCompatible(type, srcType)) + { + dest->setValue(0); + } + else + { + typeMismatchError(type, srcType); + } + } + else + { + Slice::TypePtr srcValueType = srcValue->getType(); + if(isCompatible(type, srcValueType)) + { + dest->setValue(srcValue); + } + else + { + typeMismatchError(type, srcValueType); + } + } +} + +bool +FreezeScript::AssignVisitor::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::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src); + if(b2 && b2->kind() == Slice::Builtin::KindString) + { + return true; + } + + Slice::EnumPtr e2 = Slice::EnumPtr::dynamicCast(src); + if(e2 && e1->scoped() == e2->scoped()) + { + return true; + } + + return false; + } + + assert(false); + return false; +} + +bool +FreezeScript::AssignVisitor::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) + { + error("class " + s2 + " declared but not defined"); + } + return def->isA(s1); + } + + return false; +} + +void +FreezeScript::AssignVisitor::typeMismatchError(const Slice::TypePtr& dest, const Slice::TypePtr& src) +{ + ostringstream ostr; + ostr << "unable to transform"; + if(!_context.empty()) + { + ostr << ' ' << _context; + } + ostr << " from " << typeToString(src) << " to " << typeToString(dest); + error(ostr.str()); +} + +void +FreezeScript::AssignVisitor::conversionError(const Slice::TypePtr& dest, const Slice::TypePtr& src, + const string& value) +{ + ostringstream ostr; + ostr << "unable to convert"; + if(!_context.empty()) + { + ostr << ' ' << _context; + } + ostr << " `" << value << "' from " << typeToString(src) << " to " << typeToString(dest); + error(ostr.str()); +} + +void +FreezeScript::AssignVisitor::rangeError(const string& value, const Slice::TypePtr& type) +{ + ostringstream ostr; + if(!_context.empty()) + { + ostr << _context << ' '; + } + ostr << "`" << value << "' is out of range for type " << typeToString(type); + error(ostr.str()); +} + +void +FreezeScript::AssignVisitor::error(const string& msg) +{ + _errorReporter->error(msg); +} diff --git a/cpp/src/FreezeScript/AssignVisitor.h b/cpp/src/FreezeScript/AssignVisitor.h new file mode 100644 index 00000000000..f9a4d4031d5 --- /dev/null +++ b/cpp/src/FreezeScript/AssignVisitor.h @@ -0,0 +1,59 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_ASSIGN_VISITOR_H +#define FREEZE_SCRIPT_ASSIGN_VISITOR_H + +#include <FreezeScript/Data.h> + +namespace FreezeScript +{ + +class AssignVisitor : public DataVisitor +{ +public: + + AssignVisitor(const DataPtr&, const DataFactoryPtr&, const ErrorReporterPtr&, bool, + const std::string& = std::string()); + + virtual void visitBoolean(const BooleanDataPtr&); + virtual void visitInteger(const IntegerDataPtr&); + virtual void visitDouble(const DoubleDataPtr&); + virtual void visitString(const StringDataPtr&); + virtual void visitProxy(const ProxyDataPtr&); + virtual void visitStruct(const StructDataPtr&); + virtual void visitSequence(const SequenceDataPtr&); + virtual void visitEnum(const EnumDataPtr&); + virtual void visitDictionary(const DictionaryDataPtr&); + virtual void visitObject(const ObjectRefPtr&); + +private: + + bool isCompatible(const Slice::TypePtr&, const Slice::TypePtr&); + bool checkClasses(const Slice::ClassDeclPtr&, const Slice::ClassDeclPtr&); + void typeMismatchError(const Slice::TypePtr&, const Slice::TypePtr&); + void conversionError(const Slice::TypePtr&, const Slice::TypePtr&, const std::string&); + void rangeError(const std::string&, const Slice::TypePtr&); + void error(const std::string&); + + DataPtr _src; + DataFactoryPtr _factory; + ErrorReporterPtr _errorReporter; + bool _convert; + std::string _context; // Provides additional detail for use in warning messages. +}; + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Data.cpp b/cpp/src/FreezeScript/Data.cpp new file mode 100644 index 00000000000..63d56ef8354 --- /dev/null +++ b/cpp/src/FreezeScript/Data.cpp @@ -0,0 +1,2637 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Data.h> +#include <FreezeScript/Util.h> +#include <FreezeScript/Exception.h> +#include <IceUtil/InputUtil.h> + +using namespace std; +using namespace IceUtil; + +namespace FreezeScript +{ + +// +// 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*, bool) 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 +// +FreezeScript::ObjectWriter::ObjectWriter(const ObjectDataPtr& value) : + _value(value) +{ +} + +void +FreezeScript::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 +FreezeScript::ObjectWriter::__read(IceInternal::BasicStream*, bool) +{ + assert(false); +} + +// +// ObjectReader +// +FreezeScript::ObjectReader::ObjectReader(const DataFactoryPtr& factory, const Slice::TypePtr& type) : + _factory(factory), _type(type) +{ +} + +void +FreezeScript::ObjectReader::__write(IceInternal::BasicStream*, bool) const +{ + assert(false); +} + +void +FreezeScript::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); + if(id != Ice::Object::ice_staticId()) + { + throw Ice::MarshalException(__FILE__, __LINE__); + } + } + is->startReadSlice(); + _value->_facetMap->unmarshal(*is); + is->endReadSlice(); +} + +FreezeScript::ObjectDataPtr +FreezeScript::ObjectReader::getValue() const +{ + return _value; +} + +// +// DataInitializer +// +FreezeScript::DataInitializer::~DataInitializer() +{ +} + +// +// DataFactory +// +FreezeScript::DataFactory::DataFactory(const Ice::CommunicatorPtr& communicator, const Slice::UnitPtr& unit, + const ErrorReporterPtr& errorReporter) : + _communicator(communicator), _unit(unit), _errorReporter(errorReporter), _initializersEnabled(true) +{ +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::create(const Slice::TypePtr& type, bool readOnly) +{ + DataPtr data = createImpl(type, readOnly); + if(!readOnly) + { + initialize(data); + } + return data; +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::createBoolean(bool b, bool readOnly) +{ + DataPtr data = new BooleanData(getBuiltin(Slice::Builtin::KindBool), _errorReporter, readOnly, b); + if(!readOnly) + { + initialize(data); + } + return data; +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::createInteger(Ice::Long i, bool readOnly) +{ + DataPtr data = new IntegerData(getBuiltin(Slice::Builtin::KindLong), _errorReporter, readOnly, i); + if(!readOnly) + { + initialize(data); + } + return data; +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::createDouble(double d, bool readOnly) +{ + DataPtr data = new DoubleData(getBuiltin(Slice::Builtin::KindDouble), _errorReporter, readOnly, d); + if(!readOnly) + { + initialize(data); + } + return data; +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::createString(const string& s, bool readOnly) +{ + DataPtr data = new StringData(this, getBuiltin(Slice::Builtin::KindString), _errorReporter, readOnly, s); + if(!readOnly) + { + initialize(data); + } + return data; +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::createNil(bool readOnly) +{ + DataPtr data = new ObjectRef(this, getBuiltin(Slice::Builtin::KindObject), readOnly); + if(!readOnly) + { + initialize(data); + } + return data; +} + +FreezeScript::DataPtr +FreezeScript::DataFactory::createObject(const Slice::TypePtr& type, bool readOnly) +{ + ObjectRefPtr obj; + 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"); + } + obj = new ObjectRef(this, cl, readOnly); + } + else + { + Slice::BuiltinPtr b = Slice::BuiltinPtr::dynamicCast(type); + if(b && b->kind() == Slice::Builtin::KindObject) + { + obj = new ObjectRef(this, b, readOnly); + } + } + + if(!obj) + { + _errorReporter->error("type `" + typeToString(type) + "' is not a class"); + } + + obj->instantiate(); + + if(!readOnly) + { + initialize(obj); + } + + return obj; +} + +Slice::BuiltinPtr +FreezeScript::DataFactory::getBuiltin(Slice::Builtin::Kind kind) const +{ + return _unit->builtin(kind); +} + +void +FreezeScript::DataFactory::addInitializer(const string& type, const DataInitializerPtr& init) +{ + _initializers.insert(InitMap::value_type(type, init)); +} + +void +FreezeScript::DataFactory::enableInitializers() +{ + _initializersEnabled = true; +} + +void +FreezeScript::DataFactory::disableInitializers() +{ + _initializersEnabled = false; +} + +Ice::CommunicatorPtr +FreezeScript::DataFactory::getCommunicator() const +{ + return _communicator; +} + +FreezeScript::ErrorReporterPtr +FreezeScript::DataFactory::getErrorReporter() const +{ + return _errorReporter; +} + +FreezeScript::DataPtr +FreezeScript::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; +} + +void +FreezeScript::DataFactory::initialize(const DataPtr& data) +{ + if(_initializersEnabled) + { + string name = typeToString(data->getType()); + InitMap::iterator p = _initializers.find(name); + if(p != _initializers.end()) + { + p->second->initialize(this, data, _communicator); + } + } +} + +// +// Data +// +FreezeScript::Data::Data(const ErrorReporterPtr& errorReporter, bool readOnly) : + _errorReporter(errorReporter), _readOnly(readOnly) +{ +} + +FreezeScript::Data::~Data() +{ +} + +bool +FreezeScript::Data::readOnly() const +{ + return _readOnly; +} + +// +// PrimitiveData +// +FreezeScript::PrimitiveData::PrimitiveData(const ErrorReporterPtr& errorReporter, bool readOnly) : + Data(errorReporter, readOnly) +{ +} + +FreezeScript::DataPtr +FreezeScript::PrimitiveData::getMember(const string&) const +{ + return 0; +} + +FreezeScript::DataPtr +FreezeScript::PrimitiveData::getElement(const DataPtr&) const +{ + _errorReporter->error("element requested of primitive value"); + return 0; +} + +void +FreezeScript::PrimitiveData::destroy() +{ +} + +// +// BooleanData +// +FreezeScript::BooleanData::BooleanData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter, + bool readOnly) : + PrimitiveData(errorReporter, readOnly), _type(type), _value(false) +{ +} + +FreezeScript::BooleanData::BooleanData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter, + bool readOnly, bool value) : + PrimitiveData(errorReporter, readOnly), _type(type), _value(value) +{ +} + +bool +FreezeScript::BooleanData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::BooleanData::clone() const +{ + return new BooleanData(_type, _errorReporter, _readOnly, _value); +} + +Slice::TypePtr +FreezeScript::BooleanData::getType() const +{ + return _type; +} + +void +FreezeScript::BooleanData::marshal(IceInternal::BasicStream& os) const +{ + os.write(_value); +} + +void +FreezeScript::BooleanData::unmarshal(IceInternal::BasicStream& is) +{ + is.read(_value); +} + +bool +FreezeScript::BooleanData::booleanValue(bool) const +{ + return _value; +} + +Ice::Long +FreezeScript::BooleanData::integerValue(bool) const +{ + _errorReporter->error("boolean cannot be converted to integer"); + return 0; +} + +double +FreezeScript::BooleanData::doubleValue(bool) const +{ + _errorReporter->error("boolean cannot be converted to double"); + return 0; +} + +string +FreezeScript::BooleanData::stringValue(bool convert) const +{ + if(convert) + { + return toString(); + } + else + { + return string(); + } +} + +string +FreezeScript::BooleanData::toString() const +{ + return (_value ? "true" : "false"); +} + +void +FreezeScript::BooleanData::visit(DataVisitor& visitor) +{ + visitor.visitBoolean(this); +} + +bool +FreezeScript::BooleanData::getValue() const +{ + return _value; +} + +void +FreezeScript::BooleanData::setValue(bool v) +{ + _value = v; +} + +// +// IntegerData +// +FreezeScript::IntegerData::IntegerData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter, + bool readOnly) : + PrimitiveData(errorReporter, readOnly), _type(type), _value(0) +{ +} + +FreezeScript::IntegerData::IntegerData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter, + bool readOnly, Ice::Long value) : + PrimitiveData(errorReporter, readOnly), _type(type), _value(value) +{ +} + +bool +FreezeScript::IntegerData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::IntegerData::clone() const +{ + return new IntegerData(_type, _errorReporter, _readOnly, _value); +} + +Slice::TypePtr +FreezeScript::IntegerData::getType() const +{ + return _type; +} + +void +FreezeScript::IntegerData::marshal(IceInternal::BasicStream& os) const +{ + rangeCheck(_value, true); + + 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 +FreezeScript::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 +FreezeScript::IntegerData::booleanValue(bool) const +{ + _errorReporter->error("integer cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::IntegerData::integerValue(bool) const +{ + return _value; +} + +double +FreezeScript::IntegerData::doubleValue(bool convert) const +{ + if(convert) + { + return static_cast<double>(_value); + } + else + { + _errorReporter->error("integer cannot be converted to double"); + return 0; + } +} + +string +FreezeScript::IntegerData::stringValue(bool convert) const +{ + if(convert) + { + return toString(); + } + else + { + _errorReporter->error("integer cannot be converted to string"); + return string(); + } +} + +string +FreezeScript::IntegerData::toString() const +{ + return toString(_value); +} + +void +FreezeScript::IntegerData::visit(DataVisitor& visitor) +{ + visitor.visitInteger(this); +} + +Ice::Long +FreezeScript::IntegerData::getValue() const +{ + return _value; +} + +void +FreezeScript::IntegerData::setValue(Ice::Long v, bool fatal) +{ + if(rangeCheck(v, fatal)) + { + _value = v; + } +} + +bool +FreezeScript::IntegerData::rangeCheck(Ice::Long value, bool fatal) const +{ + switch(_type->kind()) + { + case Slice::Builtin::KindByte: + { + if(value < 0 || value > 255) + { + _errorReporter->rangeError(toString(value), _type, fatal); + } + else + { + return true; + } + break; + } + + case Slice::Builtin::KindShort: + { + if(value < SHRT_MIN || value > SHRT_MAX) + { + _errorReporter->rangeError(toString(value), _type, fatal); + } + else + { + return true; + } + break; + } + + case Slice::Builtin::KindInt: + { + if(value < INT_MIN || value > INT_MAX) + { + _errorReporter->rangeError(toString(value), _type, fatal); + } + 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 +FreezeScript::IntegerData::toString(Ice::Long value) +{ + char buf[64]; +#ifdef WIN32 + sprintf(buf, "%I64d", value); +#else + sprintf(buf, "%lld", value); +#endif + return string(buf); +} + +// +// DoubleData +// +FreezeScript::DoubleData::DoubleData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter, + bool readOnly) : + PrimitiveData(errorReporter, readOnly), _type(type), _value(0) +{ +} + +FreezeScript::DoubleData::DoubleData(const Slice::BuiltinPtr& type, const ErrorReporterPtr& errorReporter, + bool readOnly, double value) : + PrimitiveData(errorReporter, readOnly), _type(type), _value(value) +{ +} + +bool +FreezeScript::DoubleData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::DoubleData::clone() const +{ + return new DoubleData(_type, _errorReporter, _readOnly, _value); +} + +Slice::TypePtr +FreezeScript::DoubleData::getType() const +{ + return _type; +} + +void +FreezeScript::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 +FreezeScript::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 +FreezeScript::DoubleData::booleanValue(bool) const +{ + _errorReporter->error("double cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::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 +FreezeScript::DoubleData::doubleValue(bool) const +{ + return _value; +} + +string +FreezeScript::DoubleData::stringValue(bool convert) const +{ + if(convert) + { + return toString(); + } + else + { + _errorReporter->error("double cannot be converted to string"); + return string(); + } +} + +string +FreezeScript::DoubleData::toString() const +{ + char buff[64]; + sprintf(buff, "%g", _value); + return string(buff); +} + +void +FreezeScript::DoubleData::visit(DataVisitor& visitor) +{ + visitor.visitDouble(this); +} + +double +FreezeScript::DoubleData::getValue() const +{ + return _value; +} + +void +FreezeScript::DoubleData::setValue(double v) +{ + _value = v; +} + +// +// StringData +// +FreezeScript::StringData::StringData(const DataFactoryPtr& factory, const Slice::BuiltinPtr& type, + const ErrorReporterPtr& errorReporter, bool readOnly) : + PrimitiveData(errorReporter, readOnly), _factory(factory), _type(type) +{ + setValue(""); +} + +FreezeScript::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); +} + +FreezeScript::DataPtr +FreezeScript::StringData::getMember(const string& member) const +{ + if(member == "length") + { + _length->setValue(static_cast<Ice::Long>(_value.size()), false); + return _length; + } + + return 0; +} + +bool +FreezeScript::StringData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::StringData::clone() const +{ + return new StringData(_factory, _type, _errorReporter, _readOnly, _value); +} + +Slice::TypePtr +FreezeScript::StringData::getType() const +{ + return _type; +} + +void +FreezeScript::StringData::marshal(IceInternal::BasicStream& os) const +{ + os.write(_value); +} + +void +FreezeScript::StringData::unmarshal(IceInternal::BasicStream& is) +{ + string s; + is.read(s); + setValue(s); +} + +bool +FreezeScript::StringData::booleanValue(bool) const +{ + _errorReporter->error("string cannot be converted to boolean"); + return false; +} + +Ice::Long +FreezeScript::StringData::integerValue(bool) const +{ + _errorReporter->error("string cannot be converted to integer"); + return 0; +} + +double +FreezeScript::StringData::doubleValue(bool) const +{ + _errorReporter->error("string cannot be converted to double"); + return 0; +} + +string +FreezeScript::StringData::stringValue(bool) const +{ + return _value; +} + +string +FreezeScript::StringData::toString() const +{ + return _value; +} + +void +FreezeScript::StringData::visit(DataVisitor& visitor) +{ + visitor.visitString(this); +} + +string +FreezeScript::StringData::getValue() const +{ + return _value; +} + +void +FreezeScript::StringData::setValue(const string& v) +{ + _value = v; +} + +// +// ProxyData +// +FreezeScript::ProxyData::ProxyData(const Slice::TypePtr& type, const Ice::CommunicatorPtr& communicator, + const ErrorReporterPtr& errorReporter, bool readOnly) : + Data(errorReporter, readOnly), _type(type), _communicator(communicator) +{ +} + +FreezeScript::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) +{ +} + +FreezeScript::DataPtr +FreezeScript::ProxyData::getMember(const string& member) const +{ + // TODO: Support members (id, facet, etc.)? + + return 0; +} + +FreezeScript::DataPtr +FreezeScript::ProxyData::getElement(const DataPtr&) const +{ + _errorReporter->error("element requested of proxy value"); + return 0; +} + +bool +FreezeScript::ProxyData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::ProxyData::clone() const +{ + return new ProxyData(_type, _communicator, _errorReporter, _readOnly, _value); +} + +Slice::TypePtr +FreezeScript::ProxyData::getType() const +{ + return _type; +} + +void +FreezeScript::ProxyData::destroy() +{ +} + +void +FreezeScript::ProxyData::marshal(IceInternal::BasicStream& os) const +{ + os.write(_value); +} + +void +FreezeScript::ProxyData::unmarshal(IceInternal::BasicStream& is) +{ + is.read(_value); +} + +bool +FreezeScript::ProxyData::booleanValue(bool) const +{ + _errorReporter->error("proxy cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::ProxyData::integerValue(bool) const +{ + _errorReporter->error("proxy cannot be converted to integer"); + return 0; +} + +double +FreezeScript::ProxyData::doubleValue(bool) const +{ + _errorReporter->error("proxy cannot be converted to double"); + return 0; +} + +string +FreezeScript::ProxyData::stringValue(bool) const +{ + _errorReporter->error("proxy cannot be converted to string"); + return string(); +} + +string +FreezeScript::ProxyData::toString() const +{ + if(_value && _str.empty()) + { + const_cast<string&>(_str) = _communicator->proxyToString(_value); + } + return _str; +} + +void +FreezeScript::ProxyData::visit(DataVisitor& visitor) +{ + visitor.visitProxy(this); +} + +Ice::ObjectPrx +FreezeScript::ProxyData::getValue() const +{ + return _value; +} + +void +FreezeScript::ProxyData::setValue(const string& str, bool fatal) +{ + try + { + _value = _communicator->stringToProxy(str); + _str = str; + } + catch(const Ice::LocalException&) + { + _errorReporter->conversionError(str, _type, fatal); + } +} + +void +FreezeScript::ProxyData::setValue(const Ice::ObjectPrx& v) +{ + _value = v; + _str.clear(); +} + + +// +// StructData +// +FreezeScript::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; + } +} + +FreezeScript::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(); + } +} + +FreezeScript::DataPtr +FreezeScript::StructData::getMember(const string& member) const +{ + DataMemberMap::const_iterator p = _members.find(member); + if(p != _members.end()) + { + return p->second; + } + + return 0; +} + +FreezeScript::DataPtr +FreezeScript::StructData::getElement(const DataPtr&) const +{ + _errorReporter->error("element requested of struct value"); + return 0; +} + +bool +FreezeScript::StructData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::StructData::clone() const +{ + return new StructData(_type, _errorReporter, _readOnly, _members); +} + +Slice::TypePtr +FreezeScript::StructData::getType() const +{ + return _type; +} + +void +FreezeScript::StructData::destroy() +{ + for(DataMemberMap::const_iterator p = _members.begin(); p != _members.end(); ++p) + { + p->second->destroy(); + } +} + +void +FreezeScript::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 +FreezeScript::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 +FreezeScript::StructData::booleanValue(bool) const +{ + _errorReporter->error("struct " + typeToString(_type) + " cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::StructData::integerValue(bool) const +{ + _errorReporter->error("struct " + typeToString(_type) + " cannot be converted to integer"); + return 0; +} + +double +FreezeScript::StructData::doubleValue(bool) const +{ + _errorReporter->error("struct " + typeToString(_type) + " cannot be converted to double"); + return 0; +} + +string +FreezeScript::StructData::stringValue(bool) const +{ + _errorReporter->error("struct " + typeToString(_type) + " cannot be converted to string"); + return string(); +} + +string +FreezeScript::StructData::toString() const +{ + return stringValue(); +} + +void +FreezeScript::StructData::visit(DataVisitor& visitor) +{ + visitor.visitStruct(this); +} + +FreezeScript::DataMemberMap& +FreezeScript::StructData::getMembers() +{ + return _members; +} + +// +// SequenceData +// +FreezeScript::SequenceData::SequenceData(const DataFactoryPtr& factory, const Slice::SequencePtr& type, + const ErrorReporterPtr& errorReporter, bool readOnly) : + Data(errorReporter, readOnly), _factory(factory), _type(type) +{ + _length = IntegerDataPtr::dynamicCast(_factory->createInteger(0, true)); +} + +FreezeScript::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 = IntegerDataPtr::dynamicCast(_factory->createInteger(static_cast<Ice::Long>(_elements.size()), true)); +} + +FreezeScript::DataPtr +FreezeScript::SequenceData::getMember(const string& member) const +{ + if(member == "length") + { + _length->setValue(static_cast<Ice::Long>(_elements.size()), false); + return _length; + } + + return 0; +} + +FreezeScript::DataPtr +FreezeScript::SequenceData::getElement(const DataPtr& element) const +{ + IntegerDataPtr i = IntegerDataPtr::dynamicCast(element); + if(!i) + { + _errorReporter->error("invalid sequence index type " + typeToString(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 +FreezeScript::SequenceData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::SequenceData::clone() const +{ + return new SequenceData(_factory, _type, _errorReporter, _readOnly, _elements); +} + +Slice::TypePtr +FreezeScript::SequenceData::getType() const +{ + return _type; +} + +void +FreezeScript::SequenceData::destroy() +{ + for(DataList::const_iterator p = _elements.begin(); p != _elements.end(); ++p) + { + (*p)->destroy(); + } +} + +void +FreezeScript::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 +FreezeScript::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->setValue(sz, false); +} + +bool +FreezeScript::SequenceData::booleanValue(bool) const +{ + _errorReporter->error("sequence " + typeToString(_type) + " cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::SequenceData::integerValue(bool) const +{ + _errorReporter->error("sequence " + typeToString(_type) + " cannot be converted to integer"); + return 0; +} + +double +FreezeScript::SequenceData::doubleValue(bool) const +{ + _errorReporter->error("sequence " + typeToString(_type) + " cannot be converted to double"); + return 0; +} + +string +FreezeScript::SequenceData::stringValue(bool) const +{ + _errorReporter->error("sequence " + typeToString(_type) + " cannot be converted to string"); + return string(); +} + +string +FreezeScript::SequenceData::toString() const +{ + return stringValue(); +} + +void +FreezeScript::SequenceData::visit(DataVisitor& visitor) +{ + visitor.visitSequence(this); +} + +FreezeScript::DataList& +FreezeScript::SequenceData::getElements() +{ + return _elements; +} + +// +// EnumData +// +FreezeScript::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()); +} + +FreezeScript::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()); +} + +FreezeScript::DataPtr +FreezeScript::EnumData::getMember(const string&) const +{ + return 0; +} + +FreezeScript::DataPtr +FreezeScript::EnumData::getElement(const DataPtr&) const +{ + _errorReporter->error("element requested of enum value"); + return 0; +} + +bool +FreezeScript::EnumData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::EnumData::clone() const +{ + return new EnumData(_type, _errorReporter, _value); +} + +Slice::TypePtr +FreezeScript::EnumData::getType() const +{ + return _type; +} + +void +FreezeScript::EnumData::destroy() +{ +} + +void +FreezeScript::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 +FreezeScript::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 +FreezeScript::EnumData::booleanValue(bool) const +{ + _errorReporter->error("enum " + typeToString(_type) + " cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::EnumData::integerValue(bool convert) const +{ + if(convert) + { + return _value; + } + else + { + _errorReporter->error("enum " + typeToString(_type) + " cannot be converted to integer"); + return 0; + } +} + +double +FreezeScript::EnumData::doubleValue(bool) const +{ + _errorReporter->error("enum " + typeToString(_type) + " cannot be converted to double"); + return 0; +} + +string +FreezeScript::EnumData::stringValue(bool) const +{ + _errorReporter->error("enum " + typeToString(_type) + " cannot be converted to string"); + return string(); +} + +string +FreezeScript::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; +} + +void +FreezeScript::EnumData::visit(DataVisitor& visitor) +{ + visitor.visitEnum(this); +} + +Ice::Int +FreezeScript::EnumData::getValue() const +{ + return _value; +} + +bool +FreezeScript::EnumData::setValue(Ice::Int v) +{ + if(v >= 0 && v < _count) + { + _value = v; + _name.clear(); + return true; + } + return false; +} + +bool +FreezeScript::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(); +} + +// +// DictionaryData +// +FreezeScript::DictionaryData::DictionaryData(const DataFactoryPtr& factory, const Slice::DictionaryPtr& type, + const ErrorReporterPtr& errorReporter, bool readOnly) : + Data(errorReporter, readOnly), _factory(factory), _type(type) +{ + _length = IntegerDataPtr::dynamicCast(_factory->createInteger(0, true)); +} + +FreezeScript::DictionaryData::DictionaryData(const DataFactoryPtr& factory, const Slice::DictionaryPtr& type, + const ErrorReporterPtr& errorReporter, bool readOnly, const DataMap& m) : + Data(errorReporter, readOnly), _factory(factory), _type(type) +{ + for(DataMap::const_iterator p = m.begin(); p != m.end(); ++p) + { + _map.insert(DataMap::value_type(p->first->clone(), p->second->clone())); + } + _length = IntegerDataPtr::dynamicCast(_factory->createInteger(static_cast<Ice::Long>(_map.size()), true)); +} + +FreezeScript::DataPtr +FreezeScript::DictionaryData::getMember(const string& member) const +{ + if(member == "length") + { + _length->setValue(static_cast<Ice::Long>(_map.size()), false); + return _length; + } + + return 0; +} + +FreezeScript::DataPtr +FreezeScript::DictionaryData::getElement(const DataPtr& element) const +{ + DataMap::const_iterator p = _map.find(element); + if(p != _map.end()) + { + return p->second; + } + + return 0; +} + +bool +FreezeScript::DictionaryData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::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 +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::DictionaryData::clone() const +{ + return new DictionaryData(_factory, _type, _errorReporter, _readOnly, _map); +} + +Slice::TypePtr +FreezeScript::DictionaryData::getType() const +{ + return _type; +} + +void +FreezeScript::DictionaryData::destroy() +{ + for(DataMap::const_iterator p = _map.begin(); p != _map.end(); ++p) + { + p->first->destroy(); + p->second->destroy(); + } +} + +void +FreezeScript::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 +FreezeScript::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->setValue(static_cast<Ice::Long>(_map.size()), false); +} + +bool +FreezeScript::DictionaryData::booleanValue(bool) const +{ + _errorReporter->error("dictionary " + typeToString(_type) + " cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::DictionaryData::integerValue(bool) const +{ + _errorReporter->error("dictionary " + typeToString(_type) + " cannot be converted to integer"); + return 0; +} + +double +FreezeScript::DictionaryData::doubleValue(bool) const +{ + _errorReporter->error("dictionary " + typeToString(_type) + " cannot be converted to double"); + return 0; +} + +string +FreezeScript::DictionaryData::stringValue(bool) const +{ + _errorReporter->error("dictionary " + typeToString(_type) + " cannot be converted to string"); + return string(); +} + +string +FreezeScript::DictionaryData::toString() const +{ + return stringValue(); +} + +void +FreezeScript::DictionaryData::visit(DataVisitor& visitor) +{ + visitor.visitDictionary(this); +} + +FreezeScript::DataMap& +FreezeScript::DictionaryData::getElements() +{ + return _map; +} + +// +// ObjectData +// +FreezeScript::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); + } +} + +FreezeScript::DataPtr +FreezeScript::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; +} + +FreezeScript::DataPtr +FreezeScript::ObjectData::getElement(const DataPtr& element) const +{ + _errorReporter->error("element requested of object value"); + return 0; +} + +bool +FreezeScript::ObjectData::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::ObjectData::operator!=(const Data& rhs) const +{ + _errorReporter->error("object comparison not supported"); + return false; +} + +bool +FreezeScript::ObjectData::operator<(const Data& rhs) const +{ + _errorReporter->error("object comparison not supported"); + return false; +} + +FreezeScript::DataPtr +FreezeScript::ObjectData::clone() const +{ + assert(false); + return 0; +} + +Slice::TypePtr +FreezeScript::ObjectData::getType() const +{ + return _type; +} + +void +FreezeScript::ObjectData::destroy() +{ + assert(false); +} + +void +FreezeScript::ObjectData::marshal(IceInternal::BasicStream& os) const +{ + if(!_marshaler) + { + const_cast<Ice::ObjectPtr&>(_marshaler) = new ObjectWriter(const_cast<ObjectData*>(this)); + } + os.write(_marshaler); +} + +void +FreezeScript::ObjectData::unmarshal(IceInternal::BasicStream& is) +{ + // + // Unmarshaling is done by ObjectReader. + // + assert(false); +} + +bool +FreezeScript::ObjectData::booleanValue(bool) const +{ + assert(false); + return 0; +} + +Ice::Long +FreezeScript::ObjectData::integerValue(bool) const +{ + assert(false); + return 0; +} + +double +FreezeScript::ObjectData::doubleValue(bool) const +{ + assert(false); + return 0; +} + +string +FreezeScript::ObjectData::stringValue(bool) const +{ + assert(false); + return string(); +} + +string +FreezeScript::ObjectData::toString() const +{ + assert(false); + return string(); +} + +void +FreezeScript::ObjectData::visit(DataVisitor& visitor) +{ + assert(false); +} + +FreezeScript::DataMemberMap& +FreezeScript::ObjectData::getMembers() +{ + return _members; +} + +void +FreezeScript::ObjectData::incRef() +{ + _refCount++; +} + +void +FreezeScript::ObjectData::decRef() +{ + assert(_refCount > 0); + _refCount--; + if(_refCount == 0) + { + destroyI(); + } +} + +void +FreezeScript::ObjectData::destroyI() +{ + DataMemberMap members = _members; + + _members.clear(); + _marshaler = 0; + + for(DataMemberMap::const_iterator p = members.begin(); p != members.end(); ++p) + { + p->second->destroy(); + } +} + +// +// ObjectRef +// +FreezeScript::ObjectRef::ObjectRef(const DataFactoryPtr& factory, const Slice::TypePtr& type, bool readOnly) : + Data(factory->getErrorReporter(), readOnly), _factory(factory), _type(type) +{ +} + +FreezeScript::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(); +} + +FreezeScript::DataPtr +FreezeScript::ObjectRef::getMember(const string& member) const +{ + if(!_value) + { + _errorReporter->error("member `" + member + "' requested of nil object"); + } + + return _value->getMember(member); +} + +FreezeScript::DataPtr +FreezeScript::ObjectRef::getElement(const DataPtr&) const +{ + _errorReporter->error("element requested of object value"); + return 0; +} + +bool +FreezeScript::ObjectRef::operator==(const Data& rhs) const +{ + return !operator!=(rhs); +} + +bool +FreezeScript::ObjectRef::operator!=(const Data& rhs) const +{ + const ObjectRef* r = dynamic_cast<const ObjectRef*>(&rhs); + if(!r) + { + _errorReporter->typeMismatchError(_type, rhs.getType(), true); + } + + // + // Reference comparison. + // + return _value.get() != r->_value.get(); +} + +bool +FreezeScript::ObjectRef::operator<(const Data& rhs) const +{ + _errorReporter->error("object comparison not supported"); + return false; +} + +FreezeScript::DataPtr +FreezeScript::ObjectRef::clone() const +{ + return new ObjectRef(_factory, _type, _value); +} + +Slice::TypePtr +FreezeScript::ObjectRef::getType() const +{ + return _type; +} + +void +FreezeScript::ObjectRef::destroy() +{ + if(_value) + { + _value->decRef(); + _value = 0; + } +} + +void +FreezeScript::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) + { + FreezeScript::ObjectRef* ref = static_cast<FreezeScript::ObjectRef*>(addr); + assert(ref); + + FreezeScript::ObjectReaderPtr reader = FreezeScript::ObjectReaderPtr::dynamicCast(v); + assert(reader); + + ref->setValue(reader->getValue()); + } +} + +void +FreezeScript::ObjectRef::unmarshal(IceInternal::BasicStream& is) +{ + is.read(patchObject, this); +} + +bool +FreezeScript::ObjectRef::booleanValue(bool) const +{ + _errorReporter->error(typeToString(_type) + " cannot be converted to boolean"); + return 0; +} + +Ice::Long +FreezeScript::ObjectRef::integerValue(bool) const +{ + _errorReporter->error(typeToString(_type) + " cannot be converted to integer"); + return 0; +} + +double +FreezeScript::ObjectRef::doubleValue(bool) const +{ + _errorReporter->error(typeToString(_type) + " cannot be converted to double"); + return 0; +} + +string +FreezeScript::ObjectRef::stringValue(bool) const +{ + _errorReporter->error(typeToString(_type) + " cannot be converted to string"); + return string(); +} + +string +FreezeScript::ObjectRef::toString() const +{ + return stringValue(); +} + +void +FreezeScript::ObjectRef::visit(DataVisitor& visitor) +{ + visitor.visitObject(this); +} + +void +FreezeScript::ObjectRef::instantiate() +{ + ObjectDataPtr data = new ObjectData(_factory, _type, _readOnly); + setValue(data); +} + +FreezeScript::ObjectDataPtr +FreezeScript::ObjectRef::getValue() const +{ + return _value; +} + +void +FreezeScript::ObjectRef::setValue(const ObjectDataPtr& value) +{ + // TODO: Type check? + ObjectDataPtr oldValue = _value; + _value = value; + if(_value) + { + _value->incRef(); + } + if(oldValue) + { + oldValue->decRef(); + } +} + +// +// ObjectFactory +// +FreezeScript::ObjectFactory::ObjectFactory(const DataFactoryPtr& factory, const Slice::UnitPtr& unit) : + _factory(factory), _unit(unit) +{ +} + +Ice::ObjectPtr +FreezeScript::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 +FreezeScript::ObjectFactory::destroy() +{ +} + +// +// DataVisitor +// +FreezeScript::DataVisitor::~DataVisitor() +{ +} + +void +FreezeScript::DataVisitor::visitBoolean(const BooleanDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitInteger(const IntegerDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitDouble(const DoubleDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitString(const StringDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitProxy(const ProxyDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitStruct(const StructDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitSequence(const SequenceDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitEnum(const EnumDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitDictionary(const DictionaryDataPtr&) +{ +} + +void +FreezeScript::DataVisitor::visitObject(const ObjectRefPtr&) +{ +} diff --git a/cpp/src/FreezeScript/Data.h b/cpp/src/FreezeScript/Data.h new file mode 100644 index 00000000000..4d0883f951f --- /dev/null +++ b/cpp/src/FreezeScript/Data.h @@ -0,0 +1,639 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_DATA_H +#define FREEZE_SCRIPT_DATA_H + +#include <Ice/Ice.h> +#include <Slice/Parser.h> +#include <FreezeScript/Error.h> + +namespace FreezeScript +{ + +class DataFactory; +typedef IceUtil::Handle<DataFactory> DataFactoryPtr; + +class Data; +typedef IceUtil::Handle<Data> DataPtr; + +class DataVisitor; + +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; + +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); + DataPtr createObject(const Slice::TypePtr&, bool); + + Slice::BuiltinPtr getBuiltin(Slice::Builtin::Kind) const; + + void addInitializer(const std::string&, const DataInitializerPtr&); + void enableInitializers(); + void disableInitializers(); + + Ice::CommunicatorPtr getCommunicator() const; + ErrorReporterPtr getErrorReporter() const; + +private: + + DataPtr createImpl(const Slice::TypePtr&, bool); + void initialize(const DataPtr&); + + 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 DataPtr clone() const = 0; + + bool readOnly() const; + virtual Slice::TypePtr getType() const = 0; + 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 visit(DataVisitor&) = 0; + +protected: + + Data(const ErrorReporterPtr&, bool); + + ErrorReporterPtr _errorReporter; + bool _readOnly; +}; + +class PrimitiveData : public Data +{ +public: + + virtual DataPtr getMember(const std::string&) const; + virtual DataPtr getElement(const DataPtr&) 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 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 visit(DataVisitor&); + + bool getValue() const; + void setValue(bool); + +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 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 visit(DataVisitor&); + + Ice::Long getValue() const; + void setValue(Ice::Long, bool); + +private: + + bool rangeCheck(Ice::Long, bool) 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 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 visit(DataVisitor&); + + double getValue() const; + void setValue(double); + +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 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 visit(DataVisitor&); + + std::string getValue() const; + void setValue(const std::string&); + +private: + + DataFactoryPtr _factory; + Slice::BuiltinPtr _type; + std::string _value; + IntegerDataPtr _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 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; + + virtual void visit(DataVisitor&); + + Ice::ObjectPrx getValue() const; + void setValue(const std::string&, bool); + void setValue(const Ice::ObjectPrx&); + +private: + + 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 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; + + virtual void visit(DataVisitor&); + + DataMemberMap& getMembers(); + +private: + + StructData(const Slice::StructPtr&, const ErrorReporterPtr&, bool, const DataMemberMap&); + + 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 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; + + virtual void visit(DataVisitor&); + + DataList& getElements(); + +private: + + SequenceData(const DataFactoryPtr&, const Slice::SequencePtr&, const ErrorReporterPtr&, bool, const DataList&); + + DataFactoryPtr _factory; + Slice::SequencePtr _type; + DataList _elements; + IntegerDataPtr _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 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; + + virtual void visit(DataVisitor&); + + Ice::Int getValue() const; + bool setValue(Ice::Int); + bool setValueAsString(const std::string&); + +private: + + 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 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; + + virtual void visit(DataVisitor&); + + DataMap& getElements(); + +private: + + DictionaryData(const DataFactoryPtr&, const Slice::DictionaryPtr&, const ErrorReporterPtr&, bool, const DataMap&); + + DataFactoryPtr _factory; + Slice::DictionaryPtr _type; + DataMap _map; + IntegerDataPtr _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 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; + + virtual void visit(DataVisitor&); + + DataMemberMap& getMembers(); + + void incRef(); + void decRef(); + +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 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; + + virtual void visit(DataVisitor&); + + void instantiate(); + ObjectDataPtr getValue() const; + void setValue(const ObjectDataPtr&); + +private: + + 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; +}; + +class ClassNotFoundException +{ +public: + + ClassNotFoundException(const std::string& s) : id(s) {} + + std::string id; +}; + +class DataVisitor +{ +public: + + virtual ~DataVisitor(); + + virtual void visitBoolean(const BooleanDataPtr&); + virtual void visitInteger(const IntegerDataPtr&); + virtual void visitDouble(const DoubleDataPtr&); + virtual void visitString(const StringDataPtr&); + virtual void visitProxy(const ProxyDataPtr&); + virtual void visitStruct(const StructDataPtr&); + virtual void visitSequence(const SequenceDataPtr&); + virtual void visitEnum(const EnumDataPtr&); + virtual void visitDictionary(const DictionaryDataPtr&); + virtual void visitObject(const ObjectRefPtr&); +}; + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Error.cpp b/cpp/src/FreezeScript/Error.cpp new file mode 100644 index 00000000000..7262827c1d6 --- /dev/null +++ b/cpp/src/FreezeScript/Error.cpp @@ -0,0 +1,193 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Error.h> +#include <FreezeScript/Exception.h> +#include <FreezeScript/Util.h> + +using namespace std; + +// +// ErrorReporter +// +FreezeScript::ErrorReporter::ErrorReporter(ostream& out, bool suppress) : + _out(out), _suppress(suppress) +{ +} + +ostream& +FreezeScript::ErrorReporter::stream() const +{ + return _out; +} + +void +FreezeScript::ErrorReporter::warning(const string& msg) +{ + ostringstream ostr; + if(!_descName.empty()) + { + ostr << "warning in <" << _descName << "> descriptor, line " << _descLine << ": " << msg << endl; + } + else + { + ostr << "warning: " << msg << endl; + } + string warn = ostr.str(); + if(_suppress) + { + map<string, bool>::iterator p = _warningHistory.find(warn); + if(p != _warningHistory.end()) + { + return; + } + _warningHistory.insert(map<string, bool>::value_type(warn, true)); + } + _out << warn; +} + +void +FreezeScript::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 Exception(__FILE__, __LINE__, ostr.str()); +} + +void +FreezeScript::ErrorReporter::typeMismatchError(const Slice::TypePtr& expected, const Slice::TypePtr& received, + bool fatal) +{ + ostringstream ostr; + ostr << "type mismatch: expected " << typeToString(expected) << " but received " << typeToString(received); + + if(fatal) + { + error(ostr.str()); + } + else + { + warning(ostr.str()); + } +} + +void +FreezeScript::ErrorReporter::conversionError(const string& value, const Slice::TypePtr& type, bool fatal) +{ + ostringstream ostr; + ostr << "unable to convert `" << value << "' to " << typeToString(type); + + if(fatal) + { + error(ostr.str()); + } + else + { + warning(ostr.str()); + } +} + +void +FreezeScript::ErrorReporter::rangeError(const string& value, const Slice::TypePtr& type, bool fatal) +{ + ostringstream ostr; + ostr << "value `" << value << "' is out of range for type " << typeToString(type); + + if(fatal) + { + error(ostr.str()); + } + else + { + warning(ostr.str()); + } +} + +void +FreezeScript::ErrorReporter::expressionSyntaxError(const string& msg) +{ + assert(!_expression.empty()); + ostringstream ostr; + ostr << "syntax error in expression `" << _expression << "': " << msg; + error(ostr.str()); +} + +void +FreezeScript::ErrorReporter::descriptorError(const string& msg, int line) +{ + ostringstream ostr; + ostr << "XML error on line " << line << ":" << endl << msg; + error(ostr.str()); +} + +void +FreezeScript::ErrorReporter::setDescriptor(const string& name, int line) +{ + _descName = name; + _descLine = line; +} + +void +FreezeScript::ErrorReporter::getDescriptor(string& name, int& line) +{ + name = _descName; + line = _descLine; +} + +void +FreezeScript::ErrorReporter::clearDescriptor() +{ + _descName.clear(); +} + +void +FreezeScript::ErrorReporter::setExpression(const string& expr) +{ + _expression = expr; +} + +void +FreezeScript::ErrorReporter::clearExpression() +{ + _expression.clear(); +} + +// +// DescriptorErrorContext +// +FreezeScript::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); +} + +FreezeScript::DescriptorErrorContext::~DescriptorErrorContext() +{ + // + // Restore the original descriptor information. + // + _errorReporter->setDescriptor(_name, _line); +} diff --git a/cpp/src/FreezeScript/Error.h b/cpp/src/FreezeScript/Error.h new file mode 100644 index 00000000000..33affea978d --- /dev/null +++ b/cpp/src/FreezeScript/Error.h @@ -0,0 +1,73 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_ERROR_H +#define FREEZE_SCRIPT_ERROR_H + +#include <Slice/Parser.h> + +namespace FreezeScript +{ + +class ErrorReporter : public IceUtil::SimpleShared +{ +public: + + ErrorReporter(std::ostream&, bool); + + 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&, bool); + void rangeError(const std::string&, const Slice::TypePtr&, bool); + 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(); + +private: + + std::ostream& _out; + bool _suppress; + std::map<std::string, bool> _warningHistory; + std::string _descName; + int _descLine; + std::string _expression; +}; +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 FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Exception.cpp b/cpp/src/FreezeScript/Exception.cpp new file mode 100644 index 00000000000..6d1eabb6f3d --- /dev/null +++ b/cpp/src/FreezeScript/Exception.cpp @@ -0,0 +1,62 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Exception.h> + +using namespace std; + +// +// Exception +// +FreezeScript::Exception::Exception(const char* file, int line, const string& reason) : + IceUtil::Exception(file, line), _reason(reason) +{ +} + +string FreezeScript::Exception::_name = "FreezeScript::Exception"; + +const string& +FreezeScript::Exception::ice_name() const +{ + return _name; +} + +void +FreezeScript::Exception::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ":\nerror occurred during transformation"; // TODO + if(!_reason.empty()) + { + out << ":\n" << _reason; + } +} + +IceUtil::Exception* +FreezeScript::Exception::ice_clone() const +{ + return new Exception(ice_file(), ice_line(), _reason); +} + +void +FreezeScript::Exception::ice_throw() const +{ + throw *this; +} + +string +FreezeScript::Exception::reason() const +{ + return _reason; +} diff --git a/cpp/src/FreezeScript/Exception.h b/cpp/src/FreezeScript/Exception.h new file mode 100644 index 00000000000..c3ab406ffb9 --- /dev/null +++ b/cpp/src/FreezeScript/Exception.h @@ -0,0 +1,43 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_EXCEPTION_H +#define FREEZE_SCRIPT_EXCEPTION_H + +#include <IceUtil/Exception.h> + +namespace FreezeScript +{ + +class Exception : public IceUtil::Exception +{ +public: + + Exception(const char*, int, const std::string&); + virtual const 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; + static std::string _name; +}; + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Functions.cpp b/cpp/src/FreezeScript/Functions.cpp new file mode 100644 index 00000000000..d1b6344e907 --- /dev/null +++ b/cpp/src/FreezeScript/Functions.cpp @@ -0,0 +1,350 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Functions.h> +#include <FreezeScript/Util.h> +#include <IceUtil/UUID.h> + +using namespace std; + +bool +FreezeScript::invokeGlobalFunction(const string& name, const DataList& args, DataPtr& result, + const DataFactoryPtr& factory, const ErrorReporterPtr& errorReporter) +{ + // + // Global function. + // + if(name == "typeOf") + { + if(args.size() != 1) + { + errorReporter->error("typeOf() requires one argument"); + } + result = factory->createString(typeToString(args.front()->getType()), false); + return true; + } + else if(name == "generateUUID") + { + if(args.size() != 0) + { + errorReporter->error("generateUUID() accepts no arguments"); + } + result = factory->createString(IceUtil::generateUUID(), false); + return true; + } + else if(name == "stringToIdentity") + { + StringDataPtr str; + if(args.size() > 0) + { + str = StringDataPtr::dynamicCast(args.front()); + } + if(args.size() != 1 || !str) + { + errorReporter->error("stringToIdentity() requires a string argument"); + } + + // + // Parse the identity string. + // + string idstr = str->stringValue(); + Ice::Identity id; + try + { + id = Ice::stringToIdentity(idstr); + } + catch(const Ice::IdentityParseException& ex) + { + errorReporter->error("error in stringToIdentity():\n" + ex.str); + } + + // + // Create a data representation of Ice::Identity. + // + Slice::UnitPtr unit = str->getType()->unit(); + Slice::TypeList l = unit->lookupType("::Ice::Identity", false); + assert(!l.empty()); + DataPtr identity = factory->create(l.front(), false); + StringDataPtr member; + member = StringDataPtr::dynamicCast(identity->getMember("name")); + assert(member); + member->setValue(id.name); + member = StringDataPtr::dynamicCast(identity->getMember("category")); + assert(member); + member->setValue(id.category); + result = identity; + return true; + } + else if(name == "identityToString") + { + StructDataPtr identity; + if(args.size() > 0) + { + identity = StructDataPtr::dynamicCast(args.front()); + } + if(identity) + { + Slice::TypePtr argType = identity->getType(); + Slice::StructPtr st = Slice::StructPtr::dynamicCast(argType); + if(!st || st->scoped() != "::Ice::Identity") + { + identity = 0; + } + } + if(args.size() != 1 || !identity) + { + errorReporter->error("identityToString() requires a argument of type ::Ice::Identity"); + } + + // + // Compose the identity. + // + Ice::Identity id; + StringDataPtr member; + member = StringDataPtr::dynamicCast(identity->getMember("name")); + assert(member); + id.name = member->stringValue(); + member = StringDataPtr::dynamicCast(identity->getMember("category")); + assert(member); + id.category = member->stringValue(); + + result = factory->createString(Ice::identityToString(id), false); + return true; + } + else if(name == "stringToProxy") + { + StringDataPtr str; + if(args.size() > 0) + { + str = StringDataPtr::dynamicCast(args.front()); + } + if(args.size() != 1 || !str) + { + errorReporter->error("stringToProxy() requires a string argument"); + } + + // + // Parse the proxy; + // + string sprx = str->stringValue(); + Ice::ObjectPrx prx; + try + { + prx = factory->getCommunicator()->stringToProxy(sprx); + } + catch(const Ice::ProxyParseException& ex) + { + errorReporter->error("error in stringToProxy():\n" + ex.str); + } + + Slice::UnitPtr unit = str->getType()->unit(); + ProxyDataPtr p = + ProxyDataPtr::dynamicCast(factory->create(unit->builtin(Slice::Builtin::KindObjectProxy), false)); + p->setValue(prx); + result = p; + return true; + } + else if(name == "proxyToString") + { + ProxyDataPtr prx; + if(args.size() > 0) + { + prx = ProxyDataPtr::dynamicCast(args.front()); + } + if(args.size() != 1 || !prx) + { + errorReporter->error("proxyToString() requires a proxy argument"); + } + + result = factory->createString(prx->toString(), false); + return true; + } + else if(name == "lowercase") + { + StringDataPtr str; + if(args.size() > 0) + { + str = StringDataPtr::dynamicCast(args.front()); + } + if(args.size() != 1 || !str) + { + errorReporter->error("lowercase() requires a string argument"); + } + string val = str->stringValue(); + transform(val.begin(), val.end(), val.begin(), ::tolower); + result = factory->createString(val, false); + return true; + } + + return false; +} + +bool +FreezeScript::invokeMemberFunction(const string& name, const DataPtr& target, const DataList& args, DataPtr& result, + const DataFactoryPtr& factory, const ErrorReporterPtr& errorReporter) +{ + // + // string + // + StringDataPtr targetStr = StringDataPtr::dynamicCast(target); + if(targetStr) + { + if(name == "find") + { + StringDataPtr argData; + IntegerDataPtr startData; + if(args.size() > 0) + { + argData = StringDataPtr::dynamicCast(args[0]); + } + if(args.size() > 1) + { + startData = IntegerDataPtr::dynamicCast(args[1]); + } + if(args.size() == 0 || args.size() > 2 || !argData || (args.size() == 2 && !startData)) + { + errorReporter->error("invalid arguments to find(string str[, int len])"); + } + string targ = targetStr->stringValue(); + string arg = argData->stringValue(); + string::size_type pos; + if(startData) + { + string::size_type start = static_cast<string::size_type>(startData->integerValue()); + pos = targ.find(arg, start); + } + else + { + pos = targ.find(arg); + } + result = factory->createInteger(pos == string::npos ? -1 : static_cast<Ice::Long>(pos), false); + return true; + } + else if(name == "substr") + { + IntegerDataPtr startData; + IntegerDataPtr lenData; + if(args.size() > 0) + { + startData = IntegerDataPtr::dynamicCast(args[0]); + } + if(args.size() > 1) + { + lenData = IntegerDataPtr::dynamicCast(args[1]); + } + if(args.size() == 0 || args.size() > 2 || !startData || (args.size() == 2 && !lenData)) + { + errorReporter->error("invalid arguments to substr(int start[, int len])"); + } + string targ = targetStr->stringValue(); + string::size_type start = static_cast<string::size_type>(startData->integerValue()); + string::size_type len = string::npos; + if(lenData) + { + len = static_cast<string::size_type>(lenData->integerValue()); + } + if(start > targ.size()) + { + ostringstream ostr; + ostr << "substr() starting position (" << start << ") is greater than string length (" + << targ.size() << ")"; + errorReporter->error(ostr.str()); + } + result = factory->createString(targ.substr(start, len), false); + return true; + } + else if(name == "replace") + { + IntegerDataPtr startData; + IntegerDataPtr lenData; + StringDataPtr strData; + if(args.size() == 3) + { + startData = IntegerDataPtr::dynamicCast(args[0]); + lenData = IntegerDataPtr::dynamicCast(args[1]); + strData = StringDataPtr::dynamicCast(args[2]); + } + if(args.size() != 3 || !startData || !lenData || !strData) + { + errorReporter->error("invalid arguments to replace(int start, int len, string val)"); + } + string targ = targetStr->stringValue(); + string::size_type start = static_cast<string::size_type>(startData->integerValue()); + string::size_type len = static_cast<string::size_type>(lenData->integerValue()); + string str = strData->stringValue(); + if(start > targ.size()) + { + ostringstream ostr; + ostr << "replace() starting position (" << start << ") is greater than string length (" + << targ.size() << ")"; + errorReporter->error(ostr.str()); + } + result = factory->createString(targ.replace(start, len, str), false); + return true; + } + + return false; + } + + // + // Object + // + ObjectRefPtr targetObj = ObjectRefPtr::dynamicCast(target); + if(targetObj) + { + if(name == "ice_isA") + { + ObjectDataPtr value = targetObj->getValue(); + if(!value) + { + errorReporter->error("ice_isA() invoked on nil object"); + } + StringDataPtr str; + if(args.size() > 0) + { + str = StringDataPtr::dynamicCast(args.front()); + } + if(args.size() != 1 || !str) + { + errorReporter->error("invalid arguments to ice_isA(string id)"); + } + + string id = str->stringValue(); + if(id == "::Ice::Object") + { + result = factory->createBoolean(true, false); + return true; + } + + Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(value->getType()); + if(!decl) + { + // + // Ice::Object + // + result = factory->createBoolean(false, false); + return true; + } + + Slice::ClassDefPtr def = decl->definition(); + assert(def); + result = factory->createBoolean(def->isA(id), false); + return true; + } + + return false; + } + + return false; +} diff --git a/cpp/src/FreezeScript/Functions.h b/cpp/src/FreezeScript/Functions.h new file mode 100644 index 00000000000..0dcb9f272b9 --- /dev/null +++ b/cpp/src/FreezeScript/Functions.h @@ -0,0 +1,31 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_FUNCTIONS_H +#define FREEZE_SCRIPT_FUNCTIONS_H + +#include <FreezeScript/Data.h> + +namespace FreezeScript +{ + +bool invokeGlobalFunction(const std::string&, const DataList&, DataPtr&, const DataFactoryPtr&, + const ErrorReporterPtr&); + +bool invokeMemberFunction(const std::string&, const DataPtr&, const DataList&, DataPtr&, const DataFactoryPtr&, + const ErrorReporterPtr&); + +} + +#endif diff --git a/cpp/src/FreezeScript/Grammar.y b/cpp/src/FreezeScript/Grammar.y new file mode 100644 index 00000000000..225be134a29 --- /dev/null +++ b/cpp/src/FreezeScript/Grammar.y @@ -0,0 +1,320 @@ +%{ + +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/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 FreezeScript; + +void +freeze_script_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="freeze_script_" + +%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_NEQ +%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 TOK_NEQ +%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_NEQ binary +{ + $$ = new BinaryNode(BinOpNotEq, 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)); +} +| entity +{ + $$ = $1; +} +| entity '.' function +{ + EntityNodePtr entity = EntityNodePtr::dynamicCast($1); + assert(entity); + FunctionNodePtr func = FunctionNodePtr::dynamicCast($3); + assert(func); + func->setTarget(entity); + $$ = $3; +} +| function +{ + $$ = $1; +} +| constant +{ + StringTokPtr stringVal = StringTokPtr::dynamicCast($1); + assert(stringVal); + $$ = new ConstantNode(stringVal->v); +} +; + +// ---------------------------------------------------------------------- +entity +// ---------------------------------------------------------------------- +: entity TOK_LBRACKET expr TOK_RBRACKET +{ + EntityNodePtr entity = EntityNodePtr::dynamicCast($1); + assert(entity); + entity->append(new ElementNode($3)); + $$ = $1; +} +| entity '.' TOK_IDENTIFIER +{ + StringTokPtr stringVal = StringTokPtr::dynamicCast($3); + assert(stringVal); + EntityNodePtr entity = EntityNodePtr::dynamicCast($1); + assert(entity); + entity->append(new IdentNode(stringVal->v)); + $$ = $1; +} +| TOK_IDENTIFIER +{ + StringTokPtr stringVal = StringTokPtr::dynamicCast($1); + assert(stringVal); + $$ = new IdentNode(stringVal->v); +} +; + +// ---------------------------------------------------------------------- +function +// ---------------------------------------------------------------------- +: TOK_IDENTIFIER TOK_LPAREN arg_list TOK_RPAREN +{ + StringTokPtr func = StringTokPtr::dynamicCast($1); + assert(func); + NodeListTokPtr args = NodeListTokPtr::dynamicCast($3); + assert(args); + $$ = new FunctionNode(func->v, args->v); +} +; + +// ---------------------------------------------------------------------- +arg_list +// ---------------------------------------------------------------------- +: arg_list ',' expr +{ + NodeListTokPtr l = NodeListTokPtr::dynamicCast($1); + assert(l); + l->v.push_back($3); + $$ = $1; +} +| expr +{ + NodeListTokPtr result = new NodeListTok; + result->v.push_back($1); + $$ = result; +} +| +{ + $$ = new NodeListTok; +} +; + +// ---------------------------------------------------------------------- +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/FreezeScript/GrammarUtil.h b/cpp/src/FreezeScript/GrammarUtil.h new file mode 100644 index 00000000000..1a438a1f573 --- /dev/null +++ b/cpp/src/FreezeScript/GrammarUtil.h @@ -0,0 +1,141 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_GRAMMAR_UTIL_H +#define FREEZE_SCRIPT_GRAMMAR_UTIL_H + +#include <FreezeScript/Parser.h> + +namespace FreezeScript +{ + +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; +class NodeListTok; + +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; +typedef ::IceUtil::Handle<NodeListTok> NodeListTokPtr; + +// ---------------------------------------------------------------------- +// Token +// ---------------------------------------------------------------------- + +class Token : public Node +{ +public: + + Token() { } + virtual DataPtr evaluate(const SymbolTablePtr&) { return 0; } + virtual void print(std::ostream&) const {} +}; + +// ---------------------------------------------------------------------- +// StringTok +// ---------------------------------------------------------------------- + +class StringTok : public Token +{ +public: + + StringTok() { } + + std::string 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; +}; + +class NodeListTok : public Token +{ +public: + + NodeListTok() { } + NodeList v; +}; + +} // End of namespace FreezeScript + +// +// Stuff for flex and bison +// + +#define YYSTYPE FreezeScript::NodePtr +#define YY_DECL int freeze_script_lex(YYSTYPE* yylvalp) +YY_DECL; +int freeze_script_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) freeze_script_error(a) + +#endif diff --git a/cpp/src/FreezeScript/Makefile b/cpp/src/FreezeScript/Makefile new file mode 100644 index 00000000000..8bcb57c0ccf --- /dev/null +++ b/cpp/src/FreezeScript/Makefile @@ -0,0 +1,57 @@ +# ********************************************************************** +# +# Copyright (c) 2004 +# 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 = ../.. + +TRANSFORMDB = $(top_srcdir)/bin/transformdb + +TARGETS = $(TRANSFORMDB) + +OBJS = Grammar.o \ + Scanner.o \ + AssignVisitor.o \ + Data.o \ + Error.o \ + Functions.o \ + Exception.o \ + Parser.o \ + Print.o \ + TransformAnalyzer.o \ + TransformDescriptors.o \ + TransformVisitor.o \ + Transformer.o \ + Util.o + +TRANSFORM_OBJS = TransformDB.o + +SRCS = $(OBJS:.o=.cpp) $(TRANSFORM_OBJS:.o=.cpp) + +HDIR = $(includedir)/FreezeScript + +include $(top_srcdir)/config/Make.rules + +CPPFLAGS := -I.. $(CPPFLAGS) $(DB_FLAGS) + +$(TRANSFORMDB): $(TRANSFORM_OBJS) $(OBJS) + rm -f $@ + $(CXX) $(LDFLAGS) -o $@ $(TRANSFORM_OBJS) $(OBJS) -lSlice -lIceXML $(LIBS) $(DB_LIBS) + +clean:: + rm -f Grammar.cpp Grammar.h + rm -f Scanner.cpp + +install:: all + $(INSTALL_PROGRAM) $(TRANSFORMDB) $(install_bindir) + +include .depend diff --git a/cpp/src/FreezeScript/Parser.cpp b/cpp/src/FreezeScript/Parser.cpp new file mode 100644 index 00000000000..a3f0db5b42c --- /dev/null +++ b/cpp/src/FreezeScript/Parser.cpp @@ -0,0 +1,691 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Parser.h> +#include <FreezeScript/GrammarUtil.h> +#include <IceUtil/Mutex.h> + +using namespace std; + +namespace FreezeScript +{ + +class EntityNodePrinter : public EntityNodeVisitor +{ +public: + + EntityNodePrinter(ostream& os) : + _os(os), _first(true) + { + } + + virtual void + visitIdentifier(const std::string& name) + { + if(_first) + { + _first = false; + } + else + { + _os << '.'; + } + _os << name; + } + + virtual void + visitElement(const NodePtr& value) + { + assert(!_first); + _os << '['; + value->print(_os); + _os << ']'; + } + +private: + + ostream& _os; + bool _first; +}; + +} // End of namespace FreezeScript + +// +// Globals required by the Bison grammar. +// +FreezeScript::DataFactoryPtr FreezeScript::parseDataFactory; +FreezeScript::ErrorReporterPtr FreezeScript::parseErrorReporter; +FreezeScript::NodePtr FreezeScript::parseResult; +int FreezeScript::parseLine; + +static string _input; +static string::size_type _pos; +static IceUtil::Mutex _parserMutex; + +// +// parseExpression +// +FreezeScript::NodePtr +FreezeScript::parseExpression(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 = freeze_script_parse(); + if(status != 0) + { + parseResult = 0; + } + + parseErrorReporter->clearExpression(); + parseErrorReporter = 0; + + return parseResult; +} + +// +// getInput supplies characters to the lexical scanner. +// +int +FreezeScript::getInput(char* buf, int maxSize) +{ + if(_pos < _input.length()) + { + buf[0] = _input[_pos]; + _pos++; + return 1; + } + else + { + return 0; + } +} + +// +// EvaluateException +// +FreezeScript::EvaluateException::EvaluateException(const char* file, int line, const string& reason) : + IceUtil::Exception(file, line), _reason(reason) +{ +} + +string FreezeScript::EvaluateException::_name = "FreezeScript::EvaluateException"; + +const string& +FreezeScript::EvaluateException::ice_name() const +{ + return _name; +} + +void +FreezeScript::EvaluateException::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ":\nerror occurred while evaluating expression"; + if(!_reason.empty()) + { + out << ":\n" << _reason; + } +} + +IceUtil::Exception* +FreezeScript::EvaluateException::ice_clone() const +{ + return new EvaluateException(ice_file(), ice_line(), _reason); +} + +void +FreezeScript::EvaluateException::ice_throw() const +{ + throw *this; +} + +string +FreezeScript::EvaluateException::reason() const +{ + return _reason; +} + +// +// SymbolTable +// +FreezeScript::SymbolTable::~SymbolTable() +{ +} + +// +// Node +// +FreezeScript::Node::~Node() +{ +} + +// +// BinaryNode +// +FreezeScript::BinaryNode::BinaryNode(BinaryOperator op, const DataFactoryPtr& factory, const NodePtr& left, + const NodePtr& right) : + _op(op), _factory(factory), _left(left), _right(right) +{ +} + +FreezeScript::DataPtr +FreezeScript::BinaryNode::evaluate(const SymbolTablePtr& 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; + } + + case BinOpNotEq: + { + 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 +FreezeScript::BinaryNode::print(ostream& os) const +{ + os << opToString(_op) << ": left="; + _left->print(os); + os << ", right="; + _right->print(os); +} + +string +FreezeScript::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 "=="; + + case BinOpNotEq: + return "!="; + } + + assert(false); + return string(); +} + +// +// UnaryNode +// +FreezeScript::UnaryNode::UnaryNode(UnaryOperator op, const DataFactoryPtr& factory, const NodePtr& right) : + _op(op), _factory(factory), _right(right) +{ +} + +FreezeScript::DataPtr +FreezeScript::UnaryNode::evaluate(const SymbolTablePtr& 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 +FreezeScript::UnaryNode::print(ostream& os) const +{ + os << opToString(_op) << ": right="; + _right->print(os); +} + +string +FreezeScript::UnaryNode::opToString(UnaryOperator op) +{ + switch(op) + { + case UnaryOpNeg: + return "-"; + + case UnaryOpNot: + return "!"; + } + + assert(false); + return string(); +} + +// +// DataNode +// +FreezeScript::DataNode::DataNode(const DataPtr& data) : + _data(data) +{ +} + +FreezeScript::DataPtr +FreezeScript::DataNode::evaluate(const SymbolTablePtr&) +{ + return _data; +} + +void +FreezeScript::DataNode::print(ostream& os) const +{ + // TODO + //_data->print(os); +} + +// +// EntityNodeVisitor +// +FreezeScript::EntityNodeVisitor::~EntityNodeVisitor() +{ +} + +// +// EntityNode +// +FreezeScript::DataPtr +FreezeScript::EntityNode::evaluate(const SymbolTablePtr& st) +{ + DataPtr result = st->getValue(this); + if(!result) + { + ostringstream ostr; + print(ostr); + throw EvaluateException(__FILE__, __LINE__, "unknown entity `" + ostr.str() + "'"); + } + return result; +} + +void +FreezeScript::EntityNode::print(ostream& os) const +{ + EntityNodePrinter printer(os); + visit(printer); +} + +void +FreezeScript::EntityNode::append(const EntityNodePtr& next) +{ + if(_next) + { + _next->append(next); + } + else + { + _next = next; + } +} + +// +// IdentNode +// +FreezeScript::IdentNode::IdentNode(const string& value) : + _value(value) +{ +} + +string +FreezeScript::IdentNode::getValue() const +{ + return _value; +} + +void +FreezeScript::IdentNode::visit(EntityNodeVisitor& visitor) const +{ + visitor.visitIdentifier(_value); + if(_next) + { + _next->visit(visitor); + } +} + +// +// ElementNode +// +FreezeScript::ElementNode::ElementNode(const NodePtr& value) : + _value(value) +{ +} + +FreezeScript::NodePtr +FreezeScript::ElementNode::getValue() const +{ + return _value; +} + +void +FreezeScript::ElementNode::visit(EntityNodeVisitor& visitor) const +{ + visitor.visitElement(_value); + if(_next) + { + _next->visit(visitor); + } +} + +// +// FunctionNode +// +FreezeScript::FunctionNode::FunctionNode(const string& name, const NodeList& args) : + _name(name), _args(args) +{ +} + +FreezeScript::DataPtr +FreezeScript::FunctionNode::evaluate(const SymbolTablePtr& st) +{ + DataPtr target; + if(_target) + { + target = _target->evaluate(st); + } + DataList args; + for(NodeList::iterator p = _args.begin(); p != _args.end(); ++p) + { + args.push_back((*p)->evaluate(st)); + } + return st->invokeFunction(_name, target, args); +} + +void +FreezeScript::FunctionNode::print(ostream& os) const +{ + if(_target) + { + _target->print(os); + os << '.'; + } + os << _name << '('; + for(NodeList::const_iterator p = _args.begin(); p != _args.end(); ++p) + { + if(p != _args.begin()) + { + os << ", "; + } + (*p)->print(os); + } + os << ')'; +} + +void +FreezeScript::FunctionNode::setTarget(const EntityNodePtr& target) +{ + _target = target; +} + +// +// ConstantNode +// +FreezeScript::ConstantNode::ConstantNode(const string& value) : + _value(value) +{ +} + +FreezeScript::DataPtr +FreezeScript::ConstantNode::evaluate(const SymbolTablePtr& st) +{ + DataPtr result = st->getConstantValue(_value); + if(!result) + { + throw EvaluateException(__FILE__, __LINE__, "unknown constant `" + _value + "'"); + } + return result; +} + +void +FreezeScript::ConstantNode::print(ostream& os) const +{ + os << _value; +} + +// +// Stream insertion for an entity node. +// +ostream& +operator<<(ostream& os, const FreezeScript::EntityNodePtr& entity) +{ + FreezeScript::EntityNodePrinter printer(os); + entity->visit(printer); + return os; +} diff --git a/cpp/src/FreezeScript/Parser.h b/cpp/src/FreezeScript/Parser.h new file mode 100644 index 00000000000..82e15e5cb1f --- /dev/null +++ b/cpp/src/FreezeScript/Parser.h @@ -0,0 +1,255 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_PARSER_H +#define FREEZE_SCRIPT_PARSER_H + +#include <FreezeScript/Data.h> + +namespace FreezeScript +{ + +class SymbolTable; +typedef IceUtil::Handle<SymbolTable> SymbolTablePtr; + +class Node; +typedef IceUtil::Handle<Node> NodePtr; + +typedef std::vector<NodePtr> NodeList; + +class EntityNode; +typedef IceUtil::Handle<EntityNode> EntityNodePtr; + +// +// parseExpression parses the given expression and returns the root node of the parse tree. +// +NodePtr parseExpression(const std::string&, const DataFactoryPtr&, const ErrorReporterPtr&); + +// +// EvaluateException is raised by Node::evaluate(). +// +class EvaluateException : public IceUtil::Exception +{ +public: + + EvaluateException(const char*, int, const std::string&); + virtual const 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; + static std::string _name; +}; + +// +// SymbolTable is an interface for the lookup operations required by node evaluation. +// +class SymbolTable : public IceUtil::SimpleShared +{ +public: + + virtual ~SymbolTable(); + + virtual void add(const std::string&, const DataPtr&) = 0; + + virtual DataPtr getValue(const EntityNodePtr&) const = 0; + + virtual DataPtr getConstantValue(const std::string&) const = 0; + + virtual SymbolTablePtr createChild() = 0; + + virtual Slice::TypePtr lookupType(const std::string&) = 0; + + virtual DataPtr invokeFunction(const std::string&, const DataPtr&, const DataList&) = 0; +}; + +class Node : public IceUtil::SimpleShared +{ +public: + + virtual ~Node(); + + virtual DataPtr evaluate(const SymbolTablePtr&) = 0; + + virtual void print(std::ostream&) const = 0; +}; + +enum BinaryOperator +{ + BinOpOr, BinOpAnd, + BinOpMul, BinOpDiv, BinOpMod, + BinOpAdd, BinOpSub, + BinOpLess, BinOpGreater, BinOpLessEq, BinOpGrEq, BinOpEq, BinOpNotEq +}; + +class BinaryNode : public Node +{ +public: + + BinaryNode(BinaryOperator, const DataFactoryPtr&, const NodePtr&, const NodePtr&); + + virtual DataPtr evaluate(const SymbolTablePtr&); + + 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(const SymbolTablePtr&); + + 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(const SymbolTablePtr&); + + virtual void print(std::ostream&) const; + +private: + + DataPtr _data; +}; + +class EntityNodeVisitor +{ +public: + + virtual ~EntityNodeVisitor(); + + virtual void visitIdentifier(const std::string&) = 0; + virtual void visitElement(const NodePtr&) = 0; +}; + +class EntityNode : public Node +{ +public: + + virtual DataPtr evaluate(const SymbolTablePtr&); + + virtual void print(std::ostream&) const; + + virtual void visit(EntityNodeVisitor&) const = 0; + + void append(const EntityNodePtr&); + +protected: + + EntityNodePtr _next; +}; + +class IdentNode : public EntityNode +{ +public: + + IdentNode(const std::string&); + + virtual void visit(EntityNodeVisitor&) const; + + std::string getValue() const; + +private: + + std::string _value; +}; +typedef IceUtil::Handle<IdentNode> IdentNodePtr; + +class ElementNode : public EntityNode +{ +public: + + ElementNode(const NodePtr&); + + virtual void visit(EntityNodeVisitor&) const; + + NodePtr getValue() const; + +private: + + NodePtr _value; +}; +typedef IceUtil::Handle<ElementNode> ElementNodePtr; + +class FunctionNode : public Node +{ +public: + + FunctionNode(const std::string&, const NodeList&); + + virtual DataPtr evaluate(const SymbolTablePtr&); + + virtual void print(std::ostream&) const; + + void setTarget(const EntityNodePtr&); + +private: + + std::string _name; + NodeList _args; + EntityNodePtr _target; +}; +typedef IceUtil::Handle<FunctionNode> FunctionNodePtr; + +class ConstantNode : public Node +{ +public: + + ConstantNode(const std::string&); + + virtual DataPtr evaluate(const SymbolTablePtr&); + + virtual void print(std::ostream&) const; + +private: + + std::string _value; +}; + +} // End of namespace FreezeScript + +std::ostream& operator<<(std::ostream&, const FreezeScript::EntityNodePtr&); + +#endif diff --git a/cpp/src/FreezeScript/Print.cpp b/cpp/src/FreezeScript/Print.cpp new file mode 100644 index 00000000000..e35be8f762a --- /dev/null +++ b/cpp/src/FreezeScript/Print.cpp @@ -0,0 +1,240 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Print.h> +#include <FreezeScript/Util.h> +#include <IceUtil/OutputUtil.h> + +using namespace std; +using namespace IceUtil; + +namespace FreezeScript +{ + +class PrintVisitor : public DataVisitor +{ +public: + + PrintVisitor(ostream&); + ~PrintVisitor(); + + virtual void visitBoolean(const BooleanDataPtr&); + virtual void visitInteger(const IntegerDataPtr&); + virtual void visitDouble(const DoubleDataPtr&); + virtual void visitString(const StringDataPtr&); + virtual void visitProxy(const ProxyDataPtr&); + virtual void visitStruct(const StructDataPtr&); + virtual void visitSequence(const SequenceDataPtr&); + virtual void visitEnum(const EnumDataPtr&); + virtual void visitDictionary(const DictionaryDataPtr&); + virtual void visitObject(const ObjectRefPtr&); + +private: + + void printObjectMembers(const Slice::ClassDefPtr&, const DataMemberMap&); + + IceUtil::Output _out; + typedef map<const ObjectData*, int> ObjectHistoryMap; + ObjectHistoryMap _objectHistory; + int _objectCount; +}; + +} // End of namespace FreezeScript + +// +// printData +// +void +FreezeScript::printData(const DataPtr& data, ostream& os) +{ + PrintVisitor visitor(os); + data->visit(visitor); +} + +// +// PrintVisitor +// +FreezeScript::PrintVisitor::PrintVisitor(ostream& os) : + _out(os), _objectCount(0) +{ +} + +FreezeScript::PrintVisitor::~PrintVisitor() +{ +} + +void +FreezeScript::PrintVisitor::visitBoolean(const BooleanDataPtr& data) +{ + _out << "bool(" << data->toString() << ")"; +} + +void +FreezeScript::PrintVisitor::visitInteger(const IntegerDataPtr& data) +{ + _out << typeToString(data->getType()) << "(" << data->toString() << ")"; +} + +void +FreezeScript::PrintVisitor::visitDouble(const DoubleDataPtr& data) +{ + _out << typeToString(data->getType()) << "(" << data->toString() << ")"; +} + +void +FreezeScript::PrintVisitor::visitString(const StringDataPtr& data) +{ + _out << "'" << data->toString() << "'"; +} + +void +FreezeScript::PrintVisitor::visitProxy(const ProxyDataPtr& data) +{ + string str = data->toString(); + _out << typeToString(data->getType()) << '(' << (str.empty() ? "nil" : str) << ')'; +} + +void +FreezeScript::PrintVisitor::visitStruct(const StructDataPtr& data) +{ + Slice::StructPtr type = Slice::StructPtr::dynamicCast(data->getType()); + assert(type); + _out << "struct " << typeToString(type); + _out << sb; + // + // Print members in order of declaration. + // + Slice::DataMemberList l = type->dataMembers(); + DataMemberMap members = data->getMembers(); + for(Slice::DataMemberList::const_iterator p = l.begin(); p != l.end(); ++p) + { + DataMemberMap::const_iterator q = members.find((*p)->name()); + assert(q != members.end()); + _out << nl; + _out << q->first << " = "; + q->second->visit(*this); + } + _out << eb; +} + +void +FreezeScript::PrintVisitor::visitSequence(const SequenceDataPtr& data) +{ + DataList& elements = data->getElements(); + _out << "sequence " << typeToString(data->getType()) << " (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)->visit(*this); + } + _out << eb; +} + +void +FreezeScript::PrintVisitor::visitEnum(const EnumDataPtr& data) +{ + _out << typeToString(data->getType()) << "(" << data->toString() << ")"; +} + +void +FreezeScript::PrintVisitor::visitDictionary(const DictionaryDataPtr& data) +{ + DataMap& map = data->getElements(); + _out << "dictionary " << typeToString(data->getType()) << " (size = " << map.size() << ")"; + _out << sb; + for(DataMap::const_iterator p = map.begin(); p != map.end(); ++p) + { + _out << nl; + p->first->visit(*this); + _out << " => "; + p->second->visit(*this); + } + _out << eb; +} + +void +FreezeScript::PrintVisitor::visitObject(const ObjectRefPtr& data) +{ + ObjectDataPtr value = data->getValue(); + if(!value) + { + _out << typeToString(data->getType()) << "(nil)"; + } + else + { + Slice::TypePtr type = value->getType(); + Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(type); // May be nil for Ice::Object + + _out << "class " << typeToString(type); + ObjectHistoryMap::iterator p = _objectHistory.find(value.get()); + if(p != _objectHistory.end()) + { + ostringstream ostr; + ostr << " (object #" << p->second << ")"; + _out << ostr.str(); + } + else + { + _objectHistory.insert(ObjectHistoryMap::value_type(value.get(), _objectCount)); + ostringstream ostr; + ostr << " (object #" << _objectCount << ")"; + _out << ostr.str(); + _objectCount++; + _out << sb; + + // + // Print Ice::Object members. + // + DataMemberMap members = value->getMembers(); + DataMemberMap::const_iterator q = members.find("ice_facets"); + assert(q != members.end()); + _out << nl << q->first << " = "; + q->second->visit(*this); + + if(decl) + { + Slice::ClassDefPtr def = decl->definition(); + assert(def); + printObjectMembers(def, members); + } + + _out << eb; + } + } +} + +void +FreezeScript::PrintVisitor::printObjectMembers(const Slice::ClassDefPtr& type, const DataMemberMap& members) +{ + Slice::ClassList bases = type->bases(); + if(!bases.empty() && !bases.front()->isAbstract()) + { + printObjectMembers(bases.front(), members); + } + + // + // Print members in order of declaration. + // + Slice::DataMemberList l = type->dataMembers(); + for(Slice::DataMemberList::const_iterator p = l.begin(); p != l.end(); ++p) + { + DataMemberMap::const_iterator q = members.find((*p)->name()); + assert(q != members.end()); + _out << nl; + _out << q->first << " = "; + q->second->visit(*this); + } +} diff --git a/cpp/src/FreezeScript/Print.h b/cpp/src/FreezeScript/Print.h new file mode 100644 index 00000000000..b4ece9e8fe3 --- /dev/null +++ b/cpp/src/FreezeScript/Print.h @@ -0,0 +1,27 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_PRINT_H +#define FREEZE_SCRIPT_PRINT_H + +#include <FreezeScript/Data.h> + +namespace FreezeScript +{ + +void printData(const DataPtr&, std::ostream&); + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Scanner.l b/cpp/src/FreezeScript/Scanner.l new file mode 100644 index 00000000000..75643e79423 --- /dev/null +++ b/cpp/src/FreezeScript/Scanner.l @@ -0,0 +1,376 @@ +%{ + +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/GrammarUtil.h> // Before Grammar.h, so that YYSTYPE is defined +#include <FreezeScript/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 FreezeScript; + +namespace FreezeScript +{ + +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="freeze_script_" +%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_NEQ; +"+" 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 FreezeScript +{ + +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 FreezeScript diff --git a/cpp/src/FreezeScript/TransformAnalyzer.cpp b/cpp/src/FreezeScript/TransformAnalyzer.cpp new file mode 100644 index 00000000000..5d056381d16 --- /dev/null +++ b/cpp/src/FreezeScript/TransformAnalyzer.cpp @@ -0,0 +1,1143 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/TransformAnalyzer.h> +#include <FreezeScript/Util.h> +#include <IceUtil/OutputUtil.h> +#include <map> + +using namespace std; +using namespace Slice; +using namespace IceUtil; + +namespace FreezeScript +{ + +// +// TransformVisitor visits the old definitions and compares them with +// the new definitions. +// +class AnalyzeTransformVisitor : public ParserVisitor +{ +public: + + AnalyzeTransformVisitor(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 AnalyzeInitVisitor : public ParserVisitor +{ +public: + + AnalyzeInitVisitor(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: + + void typeChange(const TypePtr&, const string&, const string&); + + XMLOutput& _out; + UnitPtr _oldUnit; +}; + +} + +//////////////////////////////////// +// TransformVisitor +//////////////////////////////////// + +FreezeScript::AnalyzeTransformVisitor::AnalyzeTransformVisitor(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 +FreezeScript::AnalyzeTransformVisitor::visitClassDefStart(const ClassDefPtr& v) +{ + if(v->isInterface() || v->isLocal()) + { + return false; + } + + string scoped = v->scoped(); + if(ignoreType(scoped)) + { + return false; + } + + 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->dataMembers(); + DataMemberList newMembers = newClass->dataMembers(); + compareMembers(oldMembers, newMembers); + + _out << ee; + + return false; +} + +bool +FreezeScript::AnalyzeTransformVisitor::visitStructStart(const StructPtr& v) +{ + if(v->isLocal()) + { + return false; + } + + string scoped = v->scoped(); + if(ignoreType(scoped)) + { + return false; + } + + 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 +FreezeScript::AnalyzeTransformVisitor::visitSequence(const SequencePtr& v) +{ + if(v->isLocal()) + { + return; + } + + string scoped = v->scoped(); + if(ignoreType(scoped)) + { + return; + } + + 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 +FreezeScript::AnalyzeTransformVisitor::visitDictionary(const DictionaryPtr& v) +{ + if(v->isLocal()) + { + return; + } + + string scoped = v->scoped(); + if(ignoreType(scoped)) + { + return; + } + + 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 +FreezeScript::AnalyzeTransformVisitor::visitEnum(const EnumPtr& v) +{ + if(v->isLocal()) + { + return; + } + + string scoped = v->scoped(); + if(ignoreType(scoped)) + { + return; + } + + 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 +FreezeScript::AnalyzeTransformVisitor::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<string, DataMemberPtr>((*p)->name(), *p)); + } + + for(p = newMembers.begin(); p != newMembers.end(); ++p) + { + newMap.insert(pair<string, 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 +FreezeScript::AnalyzeTransformVisitor::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) + { + if(!cl->definition()) + { + _errors.push_back("class " + cl->scoped() + " declared but not defined"); + return; + } + + // + // Allow target type of Object. + // + BuiltinPtr newb = BuiltinPtr::dynamicCast(newType); + if(newb && newb->kind() == Builtin::KindObject) + { + return; + } + + ClassDeclPtr newcl = ClassDeclPtr::dynamicCast(newType); + if(newcl) + { + if(!newcl->definition()) + { + _errors.push_back("class " + newcl->scoped() + " declared but not defined"); + return; + } + + if(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 +FreezeScript::AnalyzeTransformVisitor::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); + ProxyPtr p1 = ProxyPtr::dynamicCast(t1); + ProxyPtr p2 = ProxyPtr::dynamicCast(t2); + + if(_ignoreTypeChanges) + { + _out.nl(); + _out << "<!-- NOTICE: " << desc << " has changed from "; + if(b1) + { + _out << b1->kindAsString(); + } + else if(p1) + { + _out << p1->_class()->scoped() << '*'; + } + else + { + assert(c1); + _out << c1->kindOf() << ' ' << c1->scoped(); + } + _out << " to "; + if(b2) + { + _out << b2->kindAsString(); + } + else if(p2) + { + _out << p2->_class()->scoped() << '*'; + } + 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 if(p1) + { + ostr << p1->_class()->scoped() << '*'; + } + else + { + assert(c1); + ostr << c1->kindOf() << ' ' << c1->scoped(); + } + ostr << " to "; + if(b2) + { + ostr << b2->kindAsString(); + } + else if(p2) + { + ostr << p2->_class()->scoped() << '*'; + } + else + { + assert(c2); + ostr << c2->kindOf() << ' ' << c2->scoped(); + } + _errors.push_back(ostr.str()); + } +} + +bool +FreezeScript::AnalyzeTransformVisitor::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 +//////////////////////////////////// + +FreezeScript::AnalyzeInitVisitor::AnalyzeInitVisitor(XMLOutput& out, const UnitPtr& oldUnit) : + _out(out), _oldUnit(oldUnit) +{ +} + +bool +FreezeScript::AnalyzeInitVisitor::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()) + { + typeChange(l.front(), scoped, "class"); + } + else + { + return false; + } + } + + _out.nl(); + _out.nl(); + _out << "<!-- class " << scoped << " -->"; + _out << se("init") << attr("type", scoped); + _out << ee; + + return false; +} + +bool +FreezeScript::AnalyzeInitVisitor::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) + { + typeChange(l.front(), scoped, "struct"); + } + else + { + return false; + } + } + + _out.nl(); + _out.nl(); + _out << "<!-- struct " << scoped << " -->"; + _out << se("init") << attr("type", scoped); + _out << ee; + + return false; +} + +void +FreezeScript::AnalyzeInitVisitor::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) + { + typeChange(l.front(), scoped, "sequence"); + } + else + { + return; + } + } + + _out.nl(); + _out.nl(); + _out << "<!-- sequence " << scoped << " -->"; + _out << se("init") << attr("type", scoped); + _out << ee; +} + +void +FreezeScript::AnalyzeInitVisitor::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) + { + typeChange(l.front(), scoped, "dictionary"); + } + else + { + return; + } + } + + _out.nl(); + _out.nl(); + _out << "<!-- dictionary " << scoped << " -->"; + _out << se("init") << attr("type", scoped); + _out << ee; +} + +void +FreezeScript::AnalyzeInitVisitor::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) + { + typeChange(l.front(), scoped, "enum"); + } + else + { + return; + } + } + + _out.nl(); + _out.nl(); + _out << "<!-- enum " << scoped << " -->"; + _out << se("init") << attr("type", scoped); + _out << ee; +} + + +void +FreezeScript::AnalyzeInitVisitor::typeChange(const TypePtr& t, const string& scoped, const string& kind) +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(t); + ContainedPtr c = ContainedPtr::dynamicCast(t); + ProxyPtr p = ProxyPtr::dynamicCast(t); + + _out.nl(); + _out << "<!-- NOTICE: " << scoped << " has changed from "; + if(b) + { + _out << b->kindAsString(); + } + else if(p) + { + _out << "proxy"; + } + else + { + assert(c); + _out << c->kindOf(); + } + _out << " to " << kind << " -->"; +} + +FreezeScript::TransformAnalyzer::TransformAnalyzer(const UnitPtr& oldUnit, const UnitPtr& newUnit, + bool ignoreTypeChanges) : + _old(oldUnit), _new(newUnit), _ignoreTypeChanges(ignoreTypeChanges) +{ +} + +void +FreezeScript::TransformAnalyzer::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("transformdb"); + + AnalyzeTransformVisitor transformVisitor(out, _new, oldKey, newKey, oldValue, newValue, _ignoreTypeChanges, + missingTypes, errors); + _old->visit(&transformVisitor); + + AnalyzeInitVisitor initVisitor(out, _old); + _new->visit(&initVisitor); + + out << ee; + out << '\n'; +} diff --git a/cpp/src/FreezeScript/TransformAnalyzer.h b/cpp/src/FreezeScript/TransformAnalyzer.h new file mode 100644 index 00000000000..6415f0a26ab --- /dev/null +++ b/cpp/src/FreezeScript/TransformAnalyzer.h @@ -0,0 +1,41 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_TRANSFORM_ANALYZER_H +#define FREEZE_SCRIPT_TRANSFORM_ANALYZER_H + +#include <Slice/Parser.h> +#include <ostream> + +namespace FreezeScript +{ + +class TransformAnalyzer +{ +public: + + TransformAnalyzer(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/FreezeScript/TransformDescriptors.cpp b/cpp/src/FreezeScript/TransformDescriptors.cpp new file mode 100644 index 00000000000..8416887975a --- /dev/null +++ b/cpp/src/FreezeScript/TransformDescriptors.cpp @@ -0,0 +1,2283 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/TransformDescriptors.h> +#include <FreezeScript/AssignVisitor.h> +#include <FreezeScript/Print.h> +#include <FreezeScript/Functions.h> +#include <FreezeScript/Exception.h> +#include <FreezeScript/Util.h> +#include <IceUtil/UUID.h> +#include <db_cxx.h> + +using namespace std; + +namespace FreezeScript +{ + +class SymbolTableI; +typedef IceUtil::Handle<SymbolTableI> SymbolTableIPtr; + +class SymbolTableI : public SymbolTable +{ +public: + + SymbolTableI(const DataFactoryPtr&, const Slice::UnitPtr&, const Slice::UnitPtr&, const ErrorReporterPtr&, + TransformInfo*, const SymbolTablePtr& = SymbolTablePtr()); + + virtual void add(const string&, const DataPtr&); + + virtual DataPtr getValue(const EntityNodePtr&) const; + + virtual DataPtr getConstantValue(const string&) const; + + virtual SymbolTablePtr createChild(); + + virtual Slice::TypePtr lookupType(const string&); + + virtual DataPtr invokeFunction(const string&, const DataPtr&, const DataList&); + +private: + + DataPtr findValue(const string&) const; + + class EntityVisitor : public EntityNodeVisitor + { + public: + + EntityVisitor(SymbolTableI*); + + virtual void visitIdentifier(const string&); + virtual void visitElement(const NodePtr&); + + DataPtr getCurrent() const; + + private: + + SymbolTableI* _table; + DataPtr _current; + bool _error; + }; + + friend class EntityVisitor; + + DataFactoryPtr _factory; + Slice::UnitPtr _old; + Slice::UnitPtr _new; + ErrorReporterPtr _errorReporter; + TransformInfo* _info; + SymbolTablePtr _parent; + typedef map<string, DataPtr> DataMap; + DataMap _dataMap; + DataMap _constantCache; +}; + +class ObjectVisitor : public DataVisitor +{ +public: + + ObjectVisitor(ObjectDataMap&); + + virtual void visitStruct(const StructDataPtr&); + virtual void visitSequence(const SequenceDataPtr&); + virtual void visitDictionary(const DictionaryDataPtr&); + virtual void visitObject(const ObjectRefPtr&); + +private: + + ObjectDataMap& _map; +}; + +typedef map<string, TransformDescriptorPtr> TransformMap; +typedef map<string, Slice::TypePtr> RenameMap; + +class TransformInfoI : public TransformInfo +{ +public: + + TransformInfoI(const DataFactoryPtr&, const ErrorReporterPtr&, const Slice::UnitPtr&, const Slice::UnitPtr&); + + virtual bool doDefaultTransform(const Slice::TypePtr&); + virtual bool doBaseTransform(const Slice::ClassDefPtr&); + virtual Slice::TypePtr getRenamedType(const Slice::TypePtr&); + virtual void executeCustomTransform(const DataPtr&, const DataPtr&); + virtual bool purgeObjects(); + virtual ObjectDataMap& getObjectDataMap(); + + DataFactoryPtr factory; + ErrorReporterPtr errorReporter; + Slice::UnitPtr oldUnit; + Slice::UnitPtr newUnit; + SymbolTablePtr symbolTable; + TransformMap transformMap; + RenameMap renameMap; + ObjectDataMap objectDataMap; + Slice::TypePtr oldKeyType; + Slice::TypePtr oldValueType; + Slice::TypePtr newKeyType; + Slice::TypePtr newValueType; + Ice::CommunicatorPtr communicator; + bool purge; + Db* oldDb; + DbTxn* oldDbTxn; + Db* newDb; + DbTxn* newDbTxn; +}; + +void assignOrTransform(const DataPtr&, const DataPtr&, bool, const DataFactoryPtr&, const ErrorReporterPtr&, + TransformInfo*); + +} // End of namespace FreezeScript + +// +// Descriptor +// +FreezeScript::Descriptor::Descriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter) : + _parent(parent), _line(line), _factory(factory), _errorReporter(errorReporter) +{ +} + +FreezeScript::Descriptor::~Descriptor() +{ +} + +FreezeScript::DescriptorPtr +FreezeScript::Descriptor::parent() const +{ + return _parent; +} + +FreezeScript::NodePtr +FreezeScript::Descriptor::parse(const string& expr) const +{ + return parseExpression(expr, _factory, _errorReporter); +} + +Slice::TypePtr +FreezeScript::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 +// +FreezeScript::SetDescriptor::SetDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + Descriptor(parent, line, factory, errorReporter) +{ + DescriptorErrorContext ctx(_errorReporter, "set", _line); + + IceXML::Attributes::const_iterator p; + + string target; + p = attributes.find("target"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `target' is missing"); + } + target = p->second; + + p = attributes.find("value"); + if(p != attributes.end()) + { + _valueStr = p->second; + } + + p = attributes.find("type"); + if(p != attributes.end()) + { + _type = p->second; + } + + p = attributes.find("length"); + if(p != attributes.end()) + { + _lengthStr = p->second; + } + + p = attributes.find("convert"); + if(p != attributes.end()) + { + _convert = p->second == "true"; + } + + if(!_valueStr.empty() && !_type.empty()) + { + _errorReporter->error("attributes `value' and 'type' are mutually exclusive"); + } + + if(_valueStr.empty() && _type.empty() && _lengthStr.empty()) + { + _errorReporter->error("requires a value for attributes `value', 'type' or 'length'"); + } + + NodePtr node = parse(target); + _target = EntityNodePtr::dynamicCast(node); + if(!_target) + { + _errorReporter->error("`target' attribute is not an entity: `" + target + "'"); + } + + if(!_valueStr.empty()) + { + _value = parse(_valueStr); + } + + if(!_lengthStr.empty()) + { + _length = parse(_lengthStr); + } +} + +void +FreezeScript::SetDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "set", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::SetDescriptor::validate() +{ +} + +void +FreezeScript::SetDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + DescriptorErrorContext ctx(_errorReporter, "set", _line); + + DataPtr data = sym->getValue(_target); + if(data->readOnly()) + { + ostringstream ostr; + ostr << _target; + _errorReporter->error("target `" + ostr.str() + "' cannot be modified"); + } + + 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::TypePtr type = sym->lookupType(_type); + if(!type) + { + _errorReporter->error("type `" + _type + "' not found"); + } + value = _factory->createObject(type, false); + valueDestroyer.set(value); + } + + DataPtr length; + if(_length) + { + SequenceDataPtr seq = SequenceDataPtr::dynamicCast(data); + if(!seq) + { + ostringstream ostr; + ostr << _target; + _errorReporter->error("target `" + ostr.str() + "' is not a sequence"); + } + + try + { + length = _length->evaluate(sym); + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of length `" + _lengthStr + "' failed:\n" + ex.reason()); + } + + DataList& elements = seq->getElements(); + Ice::Long l = length->integerValue(); + if(l < 0 || l > INT_MAX) + { + _errorReporter->error("sequence length " + length->toString() + " is out of range"); + } + + DataList::size_type len = static_cast<DataList::size_type>(l); + if(len < elements.size()) + { + for(DataList::size_type i = len; i < elements.size(); ++i) + { + elements[i]->destroy(); + } + elements.resize(len); + } + else if(len > elements.size()) + { + Slice::SequencePtr seqType = Slice::SequencePtr::dynamicCast(seq->getType()); + assert(seqType); + Slice::TypePtr elemType = seqType->type(); + for(DataList::size_type i = elements.size(); i < len; ++i) + { + DataPtr v = _factory->create(elemType, false); + if(value) + { + assignOrTransform(v, value, _convert, _factory, _errorReporter, info); + } + elements.push_back(v); + } + } + } + else + { + assignOrTransform(data, value, _convert, _factory, _errorReporter, info); + } +} + +// +// DefineDescriptor +// +FreezeScript::DefineDescriptor::DefineDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes, const Slice::UnitPtr& oldUnit, + const Slice::UnitPtr& newUnit) : + Descriptor(parent, line, factory, errorReporter) +{ + DescriptorErrorContext ctx(_errorReporter, "define", _line); + + IceXML::Attributes::const_iterator p; + + p = attributes.find("name"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `name' is missing"); + } + _name = p->second; + + p = attributes.find("type"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `type' is missing"); + } + if(p->second.find("::New") != string::npos) + { + Slice::TypeList l = newUnit->lookupType(p->second.substr(5), false); + if(l.empty()) + { + _errorReporter->error("type `" + p->second + "' not found"); + } + _type = l.front(); + } + else if(p->second.find("::Old") != string::npos) + { + Slice::TypeList l = oldUnit->lookupType(p->second.substr(5), false); + if(l.empty()) + { + _errorReporter->error("type `" + p->second + "' not found"); + } + _type = l.front(); + } + else + { + Slice::TypeList l = newUnit->lookupType(p->second, false); + if(l.empty()) + { + _errorReporter->error("type `" + p->second + "' not found"); + } + _type = l.front(); + } + + p = attributes.find("value"); + if(p != attributes.end()) + { + _valueStr = p->second; + } + + p = attributes.find("length"); + if(p != attributes.end()) + { + _lengthStr = p->second; + } + + p = attributes.find("convert"); + if(p != attributes.end()) + { + _convert = p->second == "true"; + } + + if(!_valueStr.empty()) + { + _value = parse(_valueStr); + } + + if(!_lengthStr.empty()) + { + _length = parse(_lengthStr); + } +} + +void +FreezeScript::DefineDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "define", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::DefineDescriptor::validate() +{ +} + +void +FreezeScript::DefineDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + DescriptorErrorContext ctx(_errorReporter, "define", _line); + + DataPtr data = _factory->create(_type, false); + + DataPtr value; + if(_value) + { + try + { + value = _value->evaluate(sym); + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of value `" + _valueStr + "' failed:\n" + ex.reason()); + } + } + + DataPtr length; + if(_length) + { + SequenceDataPtr seq = SequenceDataPtr::dynamicCast(data); + if(!seq) + { + _errorReporter->error("length attribute specified but type is not a sequence"); + } + + try + { + length = _length->evaluate(sym); + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of length `" + _lengthStr + "' failed:\n" + ex.reason()); + } + + DataList& elements = seq->getElements(); + Ice::Long l = length->integerValue(); + if(l < 0 || l > INT_MAX) + { + _errorReporter->error("sequence length " + length->toString() + " is out of range"); + } + + DataList::size_type len = static_cast<DataList::size_type>(l); + Slice::SequencePtr seqType = Slice::SequencePtr::dynamicCast(seq->getType()); + assert(seqType); + Slice::TypePtr elemType = seqType->type(); + for(DataList::size_type i = elements.size(); i < len; ++i) + { + DataPtr v = _factory->create(elemType, false); + if(value) + { + assignOrTransform(v, value, _convert, _factory, _errorReporter, info); + } + elements.push_back(v); + } + } + else if(value) + { + assignOrTransform(data, value, _convert, _factory, _errorReporter, info); + } + + sym->add(_name, data); +} + +// +// AddDescriptor +// +FreezeScript::AddDescriptor::AddDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + Descriptor(parent, line, factory, errorReporter) +{ + DescriptorErrorContext ctx(_errorReporter, "add", _line); + + IceXML::Attributes::const_iterator p; + + string target; + p = attributes.find("target"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `target' is missing"); + } + target = p->second; + + p = attributes.find("key"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `key' is missing"); + } + _keyStr = p->second; + + p = attributes.find("value"); + if(p != attributes.end()) + { + _valueStr = 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(!_valueStr.empty() && !_type.empty()) + { + _errorReporter->error("attributes `value' and 'type' are mutually exclusive"); + } + + NodePtr node = parse(target); + _target = EntityNodePtr::dynamicCast(node); + if(!_target) + { + _errorReporter->error("`target' attribute is not an entity: `" + target + "'"); + } + + assert(!_keyStr.empty()); + _key = parse(_keyStr); + + if(!_valueStr.empty()) + { + _value = parse(_valueStr); + } +} + +void +FreezeScript::AddDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "add", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::AddDescriptor::validate() +{ +} + +void +FreezeScript::AddDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + DescriptorErrorContext ctx(_errorReporter, "add", _line); + + DataPtr data = sym->getValue(_target); + if(data->readOnly()) + { + ostringstream ostr; + ostr << _target; + _errorReporter->error("target `" + ostr.str() + "' cannot be modified"); + } + + DictionaryDataPtr dict = DictionaryDataPtr::dynamicCast(data); + if(!dict) + { + ostringstream ostr; + ostr << _target; + _errorReporter->error("target `" + ostr.str() + "' is not a dictionary"); + } + + Slice::DictionaryPtr type = Slice::DictionaryPtr::dynamicCast(dict->getType()); + assert(type); + + DataPtr key; + Destroyer<DataPtr> keyDestroyer; + try + { + DataPtr v = _key->evaluate(sym); + key = _factory->create(type->keyType(), false); + keyDestroyer.set(key); + assignOrTransform(key, v, _convert, _factory, _errorReporter, info); + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of key `" + _keyStr + "' failed:\n" + ex.reason()); + } + + if(dict->getElement(key)) + { + ostringstream ostr; + printData(key, ostr); + _errorReporter->error("key " + ostr.str() + " already exists in dictionary"); + } + + DataPtr elem = _factory->create(type->valueType(), false); + Destroyer<DataPtr> elemDestroyer(elem); + + 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::TypePtr type = sym->lookupType(_type); + if(!type) + { + _errorReporter->error("type `" + _type + "' not found"); + } + value = _factory->createObject(type, false); + valueDestroyer.set(value); + } + + if(value) + { + assignOrTransform(elem, value, _convert, _factory, _errorReporter, info); + } + DataMap& map = dict->getElements(); + map.insert(DataMap::value_type(key, elem)); + keyDestroyer.release(); + elemDestroyer.release(); +} + +// +// RemoveDescriptor +// +FreezeScript::RemoveDescriptor::RemoveDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + Descriptor(parent, line, factory, errorReporter) +{ + DescriptorErrorContext ctx(_errorReporter, "remove", _line); + + IceXML::Attributes::const_iterator p; + + string target; + p = attributes.find("target"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `target' is missing"); + } + target = p->second; + + p = attributes.find("key"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `key' is missing"); + } + _keyStr = p->second; + + NodePtr node = parse(target); + _target = EntityNodePtr::dynamicCast(node); + if(!_target) + { + _errorReporter->error("`target' attribute is not an entity: `" + target + "'"); + } + + _key = parse(_keyStr); +} + +void +FreezeScript::RemoveDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "remove", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::RemoveDescriptor::validate() +{ +} + +void +FreezeScript::RemoveDescriptor::execute(const SymbolTablePtr& sym, TransformInfo*) +{ + 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); + if(data->readOnly()) + { + ostringstream ostr; + ostr << _target; + _errorReporter->error("target `" + ostr.str() + "' cannot be modified"); + } + + DictionaryDataPtr dict = DictionaryDataPtr::dynamicCast(data); + if(!dict) + { + ostringstream ostr; + ostr << _target; + _errorReporter->error("target `" + ostr.str() + "' is not a dictionary"); + } + + DataMap& map = dict->getElements(); + DataMap::iterator p = map.find(key); + if(p != map.end()) + { + p->first->destroy(); + p->second->destroy(); + map.erase(p); + } +} + +// +// DeleteDescriptor +// +FreezeScript::DeleteDescriptor::DeleteDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, const IceXML::Attributes&) : + Descriptor(parent, line, factory, errorReporter) +{ +} + +void +FreezeScript::DeleteDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "delete", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::DeleteDescriptor::validate() +{ +} + +void +FreezeScript::DeleteDescriptor::execute(const SymbolTablePtr&, TransformInfo*) +{ + throw DeleteRecordException(); +} + +// +// FailDescriptor +// +FreezeScript::FailDescriptor::FailDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + Descriptor(parent, line, factory, errorReporter) +{ + IceXML::Attributes::const_iterator p; + + p = attributes.find("test"); + if(p != attributes.end()) + { + _testStr = p->second; + } + + p = attributes.find("message"); + if(p != attributes.end()) + { + _message = p->second; + } + + if(!_testStr.empty()) + { + _test = parse(_testStr); + } + + if(_message.empty()) + { + ostringstream ostr; + ostr << "<fail> executed at line " << line << endl; + _message = ostr.str(); + } +} + +void +FreezeScript::FailDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "fail", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::FailDescriptor::validate() +{ +} + +void +FreezeScript::FailDescriptor::execute(const SymbolTablePtr& sym, TransformInfo*) +{ + DescriptorErrorContext ctx(_errorReporter, "fail", _line); + + if(_test) + { + try + { + DataPtr b = _test->evaluate(sym); + BooleanDataPtr bd = BooleanDataPtr::dynamicCast(b); + if(!bd) + { + _errorReporter->error("expression `" + _testStr + "' does not evaluate to a boolean"); + } + if(!bd->booleanValue()) + { + return; + } + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of expression `" + _testStr + "' failed:\n" + ex.reason()); + } + } + + throw Exception(__FILE__, __LINE__, _message); +} + +// +// EchoDescriptor +// +FreezeScript::EchoDescriptor::EchoDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + Descriptor(parent, line, factory, errorReporter) +{ + IceXML::Attributes::const_iterator p; + + p = attributes.find("message"); + if(p != attributes.end()) + { + _message = p->second; + } + + p = attributes.find("value"); + if(p != attributes.end()) + { + _valueStr = p->second; + } + + if(!_valueStr.empty()) + { + _value = parse(_valueStr); + } +} + +void +FreezeScript::EchoDescriptor::addChild(const DescriptorPtr&) +{ + DescriptorErrorContext ctx(_errorReporter, "echo", _line); + _errorReporter->error("child elements are not supported"); +} + +void +FreezeScript::EchoDescriptor::validate() +{ +} + +void +FreezeScript::EchoDescriptor::execute(const SymbolTablePtr& sym, TransformInfo*) +{ + DescriptorErrorContext ctx(_errorReporter, "echo", _line); + + ostream& out = _errorReporter->stream(); + + if(!_message.empty()) + { + out << _message; + } + + if(_value) + { + DataPtr v; + try + { + v = _value->evaluate(sym); + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of value `" + _valueStr + "' failed:\n" + ex.reason()); + } + printData(v, out); + } + + out << endl; +} + +// +// ExecutableContainerDescriptor +// +FreezeScript::ExecutableContainerDescriptor::ExecutableContainerDescriptor(const DescriptorPtr& parent, int line, + const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes&, + const string& name) : + Descriptor(parent, line, factory, errorReporter), _name(name) +{ +} + +void +FreezeScript::ExecutableContainerDescriptor::addChild(const DescriptorPtr& child) +{ + _children.push_back(child); +} + +void +FreezeScript::ExecutableContainerDescriptor::validate() +{ + for(vector<DescriptorPtr>::iterator p = _children.begin(); p != _children.end(); ++p) + { + (*p)->validate(); + } +} + +void +FreezeScript::ExecutableContainerDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + for(vector<DescriptorPtr>::iterator p = _children.begin(); p != _children.end(); ++p) + { + (*p)->execute(sym, info); + } +} + +// +// IfDescriptor +// +FreezeScript::IfDescriptor::IfDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + ExecutableContainerDescriptor(parent, line, factory, errorReporter, attributes, "if"), + Descriptor(parent, line, factory, errorReporter) +{ + DescriptorErrorContext ctx(_errorReporter, "if", _line); + + IceXML::Attributes::const_iterator p = attributes.find("test"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `test' is missing"); + } + _testStr = p->second; + + _test = parse(_testStr); +} + +void +FreezeScript::IfDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + DescriptorErrorContext ctx(_errorReporter, "if", _line); + + try + { + DataPtr b = _test->evaluate(sym); + BooleanDataPtr bd = BooleanDataPtr::dynamicCast(b); + if(!bd) + { + _errorReporter->error("expression `" + _testStr + "' does not evaluate to a boolean"); + } + if(bd->booleanValue()) + { + ExecutableContainerDescriptor::execute(sym, info); + } + } + catch(const EvaluateException& ex) + { + _errorReporter->error("evaluation of conditional expression `" + _testStr + "' failed:\n" + ex.reason()); + } +} + +// +// IterateDescriptor +// +FreezeScript::IterateDescriptor::IterateDescriptor(const DescriptorPtr& parent, int line, + const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes) : + ExecutableContainerDescriptor(parent, line, factory, errorReporter, attributes, "iterate"), + Descriptor(parent, line, factory, errorReporter) +{ + DescriptorErrorContext ctx(_errorReporter, "iterate", _line); + + IceXML::Attributes::const_iterator p; + string target; + + p = attributes.find("target"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `target' is missing"); + } + 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; + } + + NodePtr node = parse(target); + _target = EntityNodePtr::dynamicCast(node); + if(!_target) + { + _errorReporter->error("`target' attribute is not an entity: `" + target + "'"); + } +} + +void +FreezeScript::IterateDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + DescriptorErrorContext ctx(_errorReporter, "iterate", _line); + + DataPtr data = sym->getValue(_target); + + DictionaryDataPtr dict = DictionaryDataPtr::dynamicCast(data); + SequenceDataPtr seq = SequenceDataPtr::dynamicCast(data); + if(!dict && !seq) + { + ostringstream ostr; + ostr << _target; + _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) + { + SymbolTablePtr elemSym = sym->createChild(); + elemSym->add(key, p->first); + elemSym->add(value, p->second); + ExecutableContainerDescriptor::execute(elemSym, info); + } + } + 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) + { + SymbolTablePtr elemSym = sym->createChild(); + elemSym->add(element, *p); + elemSym->add(index, _factory->createInteger(i, true)); + ExecutableContainerDescriptor::execute(elemSym, info); + } + } +} + +// +// TransformDescriptor +// +FreezeScript::TransformDescriptor::TransformDescriptor(const DescriptorPtr& parent, int line, + const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes, + const Slice::UnitPtr& oldUnit, const Slice::UnitPtr& newUnit) : + ExecutableContainerDescriptor(parent, line, factory, errorReporter, attributes, "transform"), + Descriptor(parent, line, factory, errorReporter), _default(true), _base(true) +{ + DescriptorErrorContext ctx(_errorReporter, "transform", _line); + + IceXML::Attributes::const_iterator p; + + string type, rename; + + p = attributes.find("type"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `type' is missing"); + } + type = p->second; + + p = attributes.find("default"); + if(p != attributes.end()) + { + if(p->second == "false") + { + _default = false; + } + } + + p = attributes.find("base"); + if(p != attributes.end()) + { + if(p->second == "false") + { + _base = false; + } + } + + p = attributes.find("rename"); + if(p != attributes.end()) + { + rename = p->second; + } + + Slice::TypeList l; + + l = newUnit->lookupType(type, false); + if(l.empty()) + { + _errorReporter->error("unable to find type `" + type + "' in new Slice definitions"); + } + else + { + _newType = l.front(); + } + + if(!rename.empty()) + { + l = oldUnit->lookupType(rename, false); + if(l.empty()) + { + _errorReporter->error("unable to find type `" + rename + "' in old Slice definitions"); + } + _renameType = l.front(); + } +} + +Slice::TypePtr +FreezeScript::TransformDescriptor::type() const +{ + return _newType; +} + +string +FreezeScript::TransformDescriptor::typeName() const +{ + return typeToString(_newType); +} + +Slice::TypePtr +FreezeScript::TransformDescriptor::renameType() const +{ + return _renameType; +} + +string +FreezeScript::TransformDescriptor::renameTypeName() const +{ + string result; + if(_renameType) + { + result = typeToString(_renameType); + } + return result; +} + +bool +FreezeScript::TransformDescriptor::doDefaultTransform() const +{ + return _default; +} + +bool +FreezeScript::TransformDescriptor::doBaseTransform() const +{ + return _base; +} + +// +// InitDescriptor +// +FreezeScript::InitDescriptor::InitDescriptor(const DescriptorPtr& parent, int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes, + const Slice::UnitPtr& oldUnit, const Slice::UnitPtr& newUnit) : + ExecutableContainerDescriptor(parent, line, factory, errorReporter, attributes, "init"), + Descriptor(parent, line, factory, errorReporter), _old(oldUnit), _new(newUnit) +{ + DescriptorErrorContext ctx(_errorReporter, "init", _line); + + IceXML::Attributes::const_iterator p = attributes.find("type"); + + string type; + + if(p == attributes.end()) + { + _errorReporter->error("required attribute `type' is missing"); + } + type = p->second; + + Slice::TypeList l = _new->lookupType(type, false); + if(l.empty()) + { + _errorReporter->error("unable to find type `" + type + "' in new Slice definitions"); + } + else + { + _type = l.front(); + } +} + +void +FreezeScript::InitDescriptor::initialize(const DataFactoryPtr& factory, const DataPtr& data, + const Ice::CommunicatorPtr& communicator) +{ + // + // Create a new symbol table for the initializer and add the value to be initialized + // as the symbol "value". + // + TransformInfo* info = 0; + + // TODO: Initialializers should have access to the main symbol table. + SymbolTablePtr sym = new SymbolTableI(factory, _old, _new, _errorReporter, info); + sym->add("value", data); + + execute(sym, info); +} + +string +FreezeScript::InitDescriptor::typeName() const +{ + return typeToString(_type); +} + +// +// RecordDescriptor +// +FreezeScript::RecordDescriptor::RecordDescriptor(const DescriptorPtr& parent, int line, + const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes, + const Slice::UnitPtr& oldUnit, const Slice::UnitPtr& newUnit) : + ExecutableContainerDescriptor(parent, line, factory, errorReporter, attributes, "record"), + Descriptor(parent, line, factory, errorReporter), _old(oldUnit), _new(newUnit) +{ +} + +void +FreezeScript::RecordDescriptor::execute(const SymbolTablePtr& sym, TransformInfo* info) +{ + TransformInfoI* infoI = dynamic_cast<TransformInfoI*>(info); + assert(infoI); + + // + // We need the Instance in order to use BasicStream. + // + IceInternal::InstancePtr instance = IceInternal::getInstance(infoI->communicator); + + // + // Temporarily add an object factory. + // + infoI->communicator->addObjectFactory(new FreezeScript::ObjectFactory(_factory, _old), ""); + + // + // Iterate over the database. + // + Dbc* dbc = 0; + infoI->oldDb->cursor(infoI->oldDbTxn, &dbc, 0); + 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 + { + transformRecord(inKey, inValue, outKey, outValue, info); + outValue.endWriteEncaps(); + Dbt dbNewKey(&outKey.b[0], outKey.b.size()), dbNewValue(&outValue.b[0], outValue.b.size()); + if(infoI->newDb->put(infoI->newDbTxn, &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(const ClassNotFoundException& ex) + { + if(!infoI->purge) + { + _errorReporter->error("class " + ex.id + " not found in new Slice definitions"); + } + else + { + // The record is deleted simply by not adding it to the new database. + _errorReporter->warning("purging database record due to missing class type " + ex.id); + } + } + } + } + catch(...) + { + if(dbc) + { + dbc->close(); + } + infoI->communicator->removeObjectFactory(""); + throw; + } + + infoI->communicator->removeObjectFactory(""); + + if(dbc) + { + dbc->close(); + } +} + +void +FreezeScript::RecordDescriptor::transformRecord(IceInternal::BasicStream& inKey, IceInternal::BasicStream& inValue, + IceInternal::BasicStream& outKey, IceInternal::BasicStream& outValue, + TransformInfo* info) +{ + TransformInfoI* infoI = dynamic_cast<TransformInfoI*>(info); + assert(infoI); + + // + // Create data representations of the old key and value types. + // + _factory->disableInitializers(); + DataPtr oldKeyData = _factory->create(infoI->oldKeyType, true); + Destroyer<DataPtr> oldKeyDataDestroyer(oldKeyData); + DataPtr oldValueData = _factory->create(infoI->oldValueType, true); + Destroyer<DataPtr> oldValueDataDestroyer(oldValueData); + + // + // Unmarshal the old key and value. + // + oldKeyData->unmarshal(inKey); + oldValueData->unmarshal(inValue); + infoI->objectDataMap.clear(); + if(infoI->oldValueType->usesClasses()) + { + inValue.readPendingObjects(); + ObjectVisitor visitor(infoI->objectDataMap); + oldValueData->visit(visitor); + } + _factory->enableInitializers(); + + // + // Create data representations of the new key and value types. + // + DataPtr newKeyData = _factory->create(infoI->newKeyType, false); + Destroyer<DataPtr> newKeyDataDestroyer(newKeyData); + DataPtr newValueData = _factory->create(infoI->newValueType, false); + Destroyer<DataPtr> newValueDataDestroyer(newValueData); + + // + // Copy the data from the old key and value to the new key and value, if possible. + // + TransformVisitor keyVisitor(oldKeyData, _factory, _errorReporter, info); + newKeyData->visit(keyVisitor); + TransformVisitor valueVisitor(oldValueData, _factory, _errorReporter, info); + newValueData->visit(valueVisitor); + + if(!_children.empty()) + { + // + // Execute the child descriptors. + // + // TODO: Revisit identifiers. + // + SymbolTablePtr st = new SymbolTableI(_factory, _old, _new, _errorReporter, info, infoI->symbolTable); + st->add("oldkey", oldKeyData); + st->add("newkey", newKeyData); + st->add("oldvalue", oldValueData); + st->add("newvalue", newValueData); + ExecutableContainerDescriptor::execute(st, info); + } + + newKeyData->marshal(outKey); + newValueData->marshal(outValue); + if(infoI->newValueType->usesClasses()) + { + outValue.writePendingObjects(); + } +} + +// +// DatabaseDescriptor +// +FreezeScript::DatabaseDescriptor::DatabaseDescriptor(const DescriptorPtr& parent, int line, + const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes, + const Slice::UnitPtr& oldUnit, const Slice::UnitPtr& newUnit) : + ExecutableContainerDescriptor(parent, line, factory, errorReporter, attributes, "database"), + Descriptor(parent, line, factory, errorReporter), _old(oldUnit), _new(newUnit) +{ + DescriptorErrorContext ctx(_errorReporter, "database", _line); + + IceXML::Attributes::const_iterator p = attributes.find("key"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `key' is missing"); + } + string keyTypes = p->second; + + p = attributes.find("value"); + if(p == attributes.end()) + { + _errorReporter->error("required attribute `value' is missing"); + } + string valueTypes = p->second; + + 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(_old, oldKeyName); + _newKey = findType(_new, newKeyName); + _oldValue = findType(_old, oldValueName); + _newValue = findType(_new, newValueName); +} + +void +FreezeScript::DatabaseDescriptor::addChild(const DescriptorPtr& child) +{ + DescriptorErrorContext ctx(_errorReporter, "database", _line); + + RecordDescriptorPtr rec = RecordDescriptorPtr::dynamicCast(child); + if(rec) + { + if(_record) + { + _errorReporter->error("only one <record> element can be specified"); + } + _record = rec; + } + + ExecutableContainerDescriptor::addChild(child); +} + +void +FreezeScript::DatabaseDescriptor::execute(const SymbolTablePtr&, TransformInfo* info) +{ + TransformInfoI* infoI = dynamic_cast<TransformInfoI*>(info); + assert(infoI); + + // + // Store the key and value types. + // + infoI->oldKeyType = _oldKey; + infoI->oldValueType = _oldValue; + infoI->newKeyType = _newKey; + infoI->newValueType = _newValue; + + ExecutableContainerDescriptor::execute(infoI->symbolTable, info); +} + +// +// TransformDBDescriptor +// +FreezeScript::TransformDBDescriptor::TransformDBDescriptor(int line, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, + const IceXML::Attributes& attributes, + const Slice::UnitPtr& oldUnit, + const Slice::UnitPtr& newUnit) : + Descriptor(0, line, factory, errorReporter), _old(oldUnit), _new(newUnit), + _info(new TransformInfoI(factory, errorReporter, oldUnit, newUnit)) +{ +} + +FreezeScript::TransformDBDescriptor::~TransformDBDescriptor() +{ + delete _info; +} + +void +FreezeScript::TransformDBDescriptor::addChild(const DescriptorPtr& child) +{ + DescriptorErrorContext ctx(_errorReporter, "transformdb", _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->typeName(); + TransformMap::iterator p = _info->transformMap.find(name); + if(p != _info->transformMap.end()) + { + _errorReporter->error("transform `" + name + "' specified more than once"); + } + _info->transformMap.insert(TransformMap::value_type(name, transform)); + + string renameTypeName = transform->renameTypeName(); + if(!renameTypeName.empty()) + { + RenameMap::iterator q = _info->renameMap.find(renameTypeName); + if(q != _info->renameMap.end()) + { + _errorReporter->error("multiple transform descriptors specify the rename value `" + renameTypeName + + "'"); + } + _info->renameMap.insert(RenameMap::value_type(renameTypeName, transform->type())); + } + + _children.push_back(transform); + } + else if(init) + { + string name = init->typeName(); + _factory->addInitializer(name, init); + _children.push_back(init); + } + else + { + _errorReporter->error("invalid child element"); + } +} + +void +FreezeScript::TransformDBDescriptor::validate() +{ + DescriptorErrorContext ctx(_errorReporter, "transformdb", _line); + + if(!_database) + { + _errorReporter->error("no <database> element specified"); + } + + for(vector<DescriptorPtr>::iterator p = _children.begin(); p != _children.end(); ++p) + { + (*p)->validate(); + } +} + +void +FreezeScript::TransformDBDescriptor::execute(const SymbolTablePtr&, TransformInfo*) +{ + assert(false); +} + +void +FreezeScript::TransformDBDescriptor::transform(const Ice::CommunicatorPtr& communicator, Db* oldDb, DbTxn* oldDbTxn, + Db* newDb, DbTxn* newDbTxn, bool purgeObjects) +{ + _info->communicator = communicator; + _info->oldDb = oldDb; + _info->oldDbTxn = oldDbTxn; + _info->newDb = newDb; + _info->newDbTxn = newDbTxn; + _info->purge = purgeObjects; + + try + { + _database->execute(0, _info); + } + catch(...) + { + _info->communicator = 0; + _info->oldDb = 0; + _info->oldDbTxn = 0; + _info->newDb = 0; + _info->newDbTxn = 0; + throw; + } + + _info->communicator = 0; + _info->oldDb = 0; + _info->oldDbTxn = 0; + _info->newDb = 0; + _info->newDbTxn = 0; +} + +// +// SymbolTableI +// +FreezeScript::SymbolTableI::SymbolTableI(const DataFactoryPtr& factory, const Slice::UnitPtr& oldUnit, + const Slice::UnitPtr& newUnit, + const ErrorReporterPtr& errorReporter, TransformInfo* info, + const SymbolTablePtr& parent) : + _factory(factory), _old(oldUnit), _new(newUnit), _errorReporter(errorReporter), _info(info), _parent(parent) +{ +} + +void +FreezeScript::SymbolTableI::add(const string& name, const DataPtr& data) +{ + DataPtr d = findValue(name); + if(d) + { + _errorReporter->error("`" + name + "' is already defined"); + } + + _dataMap.insert(DataMap::value_type(name, data)); +} + +FreezeScript::DataPtr +FreezeScript::SymbolTableI::getValue(const EntityNodePtr& entity) const +{ + EntityVisitor visitor(const_cast<SymbolTableI*>(this)); + entity->visit(visitor); + DataPtr result = visitor.getCurrent(); + if(!result) + { + ostringstream ostr; + ostr << "invalid entity `" << entity << "'"; + _errorReporter->error(ostr.str()); + } + + return result; +} + +FreezeScript::DataPtr +FreezeScript::SymbolTableI::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()) + { + _errorReporter->error("invalid constant name `" + name + "'"); + } + + Slice::ContainedList l = unit->findContents(key); + if(l.empty()) + { + _errorReporter->error("unknown constant `" + name + "'"); + } + + Slice::EnumeratorPtr e = Slice::EnumeratorPtr::dynamicCast(l.front()); + Slice::ConstPtr c = Slice::ConstPtr::dynamicCast(l.front()); + if(!e && !c) + { + _errorReporter->error("`" + 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 end; + Ice::Long n; + if(!IceUtil::stringToInt64(value, n, end)) + { + assert(false); + } + 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 q = el.begin(); q != el.end(); ++q) + { + if((*q)->name() == value) + { + e = *q; + 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; +} + +FreezeScript::SymbolTablePtr +FreezeScript::SymbolTableI::createChild() +{ + return new SymbolTableI(_factory, _old, _new, _errorReporter, _info, this); +} + +Slice::TypePtr +FreezeScript::SymbolTableI::lookupType(const string& name) +{ + Slice::TypeList l = _new->lookupType(name, false); + Slice::TypePtr result; + if(!l.empty()) + { + result = l.front(); + } + return result; +} + +FreezeScript::DataPtr +FreezeScript::SymbolTableI::invokeFunction(const string& name, const DataPtr& target, const DataList& args) +{ + if(target) + { + DictionaryDataPtr targetDict = DictionaryDataPtr::dynamicCast(target); + if(targetDict && name == "containsKey") + { + if(args.size() != 1) + { + _errorReporter->error("containsKey() requires one argument"); + } + Slice::DictionaryPtr dictType = Slice::DictionaryPtr::dynamicCast(targetDict->getType()); + assert(dictType); + DataPtr key = _factory->create(dictType->keyType(), false); + assignOrTransform(key, args[0], false, _factory, _errorReporter, _info); + DataPtr value = targetDict->getElement(key); + return _factory->createBoolean(value ? true : false, false); + } + + DataPtr result; + if(invokeMemberFunction(name, target, args, result, _factory, _errorReporter)) + { + return result; + } + + _errorReporter->error("unknown function `" + name + "' invoked on type " + typeToString(target->getType())); + } + else + { + // + // Global function. + // + DataPtr result; + if(invokeGlobalFunction(name, args, result, _factory, _errorReporter)) + { + return result; + } + else + { + _errorReporter->error("unknown global function `" + name + "'"); + } + } + + return 0; +} + +FreezeScript::DataPtr +FreezeScript::SymbolTableI::findValue(const string& name) const +{ + DataMap::const_iterator p = _dataMap.find(name); + if(p != _dataMap.end()) + { + return p->second; + } + + if(_parent) + { + SymbolTableIPtr parentI = SymbolTableIPtr::dynamicCast(_parent); + assert(parentI); + return parentI->findValue(name); + } + + return 0; +} + +FreezeScript::SymbolTableI::EntityVisitor::EntityVisitor(SymbolTableI* table) : + _table(table), _error(false) +{ +} + +void +FreezeScript::SymbolTableI::EntityVisitor::visitIdentifier(const string& name) +{ + if(!_error) + { + if(!_current) + { + _current = _table->findValue(name); + } + else + { + _current = _current->getMember(name); + } + + if(!_current) + { + _error = true; + } + } +} + +void +FreezeScript::SymbolTableI::EntityVisitor::visitElement(const NodePtr& value) +{ + if(!_error) + { + assert(_current); + + DataPtr val = value->evaluate(_table); + _current = _current->getElement(val); + + if(!_current) + { + _error = true; + } + } +} + +FreezeScript::DataPtr +FreezeScript::SymbolTableI::EntityVisitor::getCurrent() const +{ + return _current; +} + +// +// ObjectVisitor +// +FreezeScript::ObjectVisitor::ObjectVisitor(ObjectDataMap& map) : + _map(map) +{ +} + +void +FreezeScript::ObjectVisitor::visitStruct(const StructDataPtr& data) +{ + Slice::TypePtr type = data->getType(); + if(type->usesClasses()) + { + DataMemberMap& members = data->getMembers(); + for(DataMemberMap::iterator p = members.begin(); p != members.end(); ++p) + { + p->second->visit(*this); + } + } +} + +void +FreezeScript::ObjectVisitor::visitSequence(const SequenceDataPtr& data) +{ + Slice::TypePtr type = data->getType(); + if(type->usesClasses()) + { + DataList& elements = data->getElements(); + for(DataList::iterator p = elements.begin(); p != elements.end(); ++p) + { + (*p)->visit(*this); + } + } +} + +void +FreezeScript::ObjectVisitor::visitDictionary(const DictionaryDataPtr& data) +{ + Slice::TypePtr type = data->getType(); + if(type->usesClasses()) + { + DataMap& elements = data->getElements(); + for(DataMap::iterator p = elements.begin(); p != elements.end(); ++p) + { + // + // NOTE: There's no need to visit the key. + // + p->second->visit(*this); + } + } +} + +void +FreezeScript::ObjectVisitor::visitObject(const ObjectRefPtr& data) +{ + ObjectDataPtr value = data->getValue(); + if(value) + { + ObjectDataMap::iterator p = _map.find(value.get()); + if(p == _map.end()) + { + _map.insert(ObjectDataMap::value_type(value.get(), 0)); + DataMemberMap& members = value->getMembers(); + for(DataMemberMap::iterator q = members.begin(); q != members.end(); ++q) + { + q->second->visit(*this); + } + } + } +} + +// +// TransformInfoI +// +FreezeScript::TransformInfoI::TransformInfoI(const DataFactoryPtr& fact, const ErrorReporterPtr& err, + const Slice::UnitPtr& oldU, const Slice::UnitPtr& newU) : + factory(fact), errorReporter(err), oldUnit(oldU), newUnit(newU), purge(false), oldDb(0), oldDbTxn(0), newDb(0), + newDbTxn(0) +{ + symbolTable = new SymbolTableI(factory, oldUnit, newUnit, errorReporter, this); +} + +bool +FreezeScript::TransformInfoI::doDefaultTransform(const Slice::TypePtr& type) +{ + TransformMap::const_iterator p = transformMap.find(typeToString(type)); + if(p != transformMap.end()) + { + return p->second->doDefaultTransform(); + } + return true; +} + +bool +FreezeScript::TransformInfoI::doBaseTransform(const Slice::ClassDefPtr& type) +{ + TransformMap::const_iterator p = transformMap.find(type->scoped()); + if(p != transformMap.end()) + { + return p->second->doBaseTransform(); + } + return true; +} + +Slice::TypePtr +FreezeScript::TransformInfoI::getRenamedType(const Slice::TypePtr& old) +{ + RenameMap::iterator p = renameMap.find(typeToString(old)); + if(p != renameMap.end()) + { + return p->second; + } + return 0; +} + +void +FreezeScript::TransformInfoI::executeCustomTransform(const DataPtr& dest, const DataPtr& src) +{ + // + // Execute the type's transform (if any). Non-nil objects need special consideration, + // for two reasons: + // + // 1. The dest and src arguments are ObjectRef instances whose getType() + // function returns the formal type, which may not match the actual type + // if inheritance is being used. Therefore, we need to look for the + // transform of the actual type of the object. + // + // 2. It's not sufficient to execute only the transform for the actual type; + // the transform descriptors for base types must also be executed (if not + // explicitly precluded). + // + // The algorithm goes like this: + // + // 1. If a transform exists for the actual type, execute it. + // 2. If the transform doesn't exist, or if it does exist and does not preclude + // the execution of the base transform, then obtain the base type. If the + // type has no user-defined base class, use Object. + // 3. If a base type was found and a transform exists for the base type, execute it. + // 4. Repeat step 2. + // + ObjectRefPtr obj = ObjectRefPtr::dynamicCast(dest); + if(obj && obj->getValue()) + { + ObjectDataPtr data = obj->getValue(); + Slice::TypePtr cls = data->getType(); // Actual type + bool transformBase = true; + while(cls) + { + string type = typeToString(cls); + TransformMap::const_iterator p = transformMap.find(type); + if(p != transformMap.end()) + { + SymbolTablePtr sym = new SymbolTableI(factory, oldUnit, newUnit, errorReporter, this, symbolTable); + sym->add("new", dest); + sym->add("old", src); + p->second->execute(sym, this); + transformBase = p->second->doBaseTransform(); + } + Slice::ClassDeclPtr decl = Slice::ClassDeclPtr::dynamicCast(cls); + cls = 0; + if(transformBase && decl) + { + Slice::ClassDefPtr def = decl->definition(); + assert(def); + Slice::ClassList bases = def->bases(); + if(!bases.empty() && !bases.front()->isInterface()) + { + cls = bases.front()->declaration(); + } + else + { + cls = newUnit->builtin(Slice::Builtin::KindObject); + } + } + } + } + else + { + string type = typeToString(dest->getType()); + TransformMap::const_iterator p = transformMap.find(type); + if(p != transformMap.end()) + { + SymbolTablePtr sym = new SymbolTableI(factory, oldUnit, newUnit, errorReporter, this, symbolTable); + sym->add("new", dest); + sym->add("old", src); + p->second->execute(sym, this); + } + } +} + +bool +FreezeScript::TransformInfoI::purgeObjects() +{ + return purge; +} + +FreezeScript::ObjectDataMap& +FreezeScript::TransformInfoI::getObjectDataMap() +{ + return objectDataMap; +} + +// +// assignOrTransform +// +void +FreezeScript::assignOrTransform(const DataPtr& dest, const DataPtr& src, bool convert, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, TransformInfo* info) +{ + Slice::TypePtr destType = dest->getType(); + Slice::TypePtr srcType = src->getType(); + Slice::BuiltinPtr b1 = Slice::BuiltinPtr::dynamicCast(destType); + Slice::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(srcType); + + if(!b1 && !b2 && dest->getType()->unit().get() != src->getType()->unit().get()) + { + TransformVisitor v(src, factory, errorReporter, info); + dest->visit(v); + } + else + { + AssignVisitor v(src, factory, errorReporter, convert); + dest->visit(v); + } +} diff --git a/cpp/src/FreezeScript/TransformDescriptors.h b/cpp/src/FreezeScript/TransformDescriptors.h new file mode 100644 index 00000000000..d0d33085796 --- /dev/null +++ b/cpp/src/FreezeScript/TransformDescriptors.h @@ -0,0 +1,353 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_TRANSFORM_DESCRIPTORS_H +#define FREEZE_SCRIPT_TRANSFORM_DESCRIPTORS_H + +#include <FreezeScript/Parser.h> +#include <FreezeScript/TransformVisitor.h> +#include <IceXML/Parser.h> + +class Db; +class DbTxn; + +namespace FreezeScript +{ + +class Descriptor; +typedef IceUtil::Handle<Descriptor> DescriptorPtr; + +class DeleteRecordException {}; + +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(const SymbolTablePtr&, TransformInfo*) = 0; + +protected: + + Descriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&); + + NodePtr parse(const std::string&) const; + + Slice::TypePtr findType(const Slice::UnitPtr&, const std::string&); + + DescriptorPtr _parent; + int _line; + DataFactoryPtr _factory; + ErrorReporterPtr _errorReporter; +}; + +class SetDescriptor : public Descriptor +{ +public: + + SetDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + EntityNodePtr _target; + NodePtr _value; + std::string _valueStr; + std::string _type; + NodePtr _length; + std::string _lengthStr; + bool _convert; +}; + +class DefineDescriptor : public Descriptor +{ +public: + + DefineDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&, const Slice::UnitPtr&, const Slice::UnitPtr&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + std::string _name; + NodePtr _value; + std::string _valueStr; + Slice::TypePtr _type; + NodePtr _length; + std::string _lengthStr; + bool _convert; +}; + +class AddDescriptor : public Descriptor +{ +public: + + AddDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + EntityNodePtr _target; + NodePtr _key; + std::string _keyStr; + NodePtr _value; + std::string _valueStr; + std::string _type; + bool _convert; +}; + +class RemoveDescriptor : public Descriptor +{ +public: + + RemoveDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + EntityNodePtr _target; + NodePtr _key; + std::string _keyStr; +}; + +class DeleteDescriptor : public Descriptor +{ +public: + + DeleteDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); +}; + +class FailDescriptor : public Descriptor +{ +public: + + FailDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + NodePtr _test; + std::string _testStr; + std::string _message; +}; + +class EchoDescriptor : public Descriptor +{ +public: + + EchoDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + std::string _message; + NodePtr _value; + std::string _valueStr; +}; + +class ExecutableContainerDescriptor : virtual public Descriptor +{ +public: + + ExecutableContainerDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&, const std::string&); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +protected: + + std::vector<DescriptorPtr> _children; + +private: + + std::string _name; +}; + +class IfDescriptor : public ExecutableContainerDescriptor +{ +public: + + IfDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, const IceXML::Attributes&); + + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + NodePtr _test; + std::string _testStr; +}; + +class IterateDescriptor : public ExecutableContainerDescriptor +{ +public: + + IterateDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&); + + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + EntityNodePtr _target; + std::string _key; + std::string _value; + std::string _element; + std::string _index; +}; + +class TransformDescriptor : public ExecutableContainerDescriptor +{ +public: + + TransformDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&, const Slice::UnitPtr&, const Slice::UnitPtr&); + + Slice::TypePtr type() const; + std::string typeName() const; + Slice::TypePtr renameType() const; + std::string renameTypeName() const; + bool doDefaultTransform() const; + bool doBaseTransform() const; + +private: + + bool _default; + bool _base; + Slice::TypePtr _newType; + Slice::TypePtr _renameType; +}; +typedef IceUtil::Handle<TransformDescriptor> TransformDescriptorPtr; + +class InitDescriptor : virtual public ExecutableContainerDescriptor, virtual public DataInitializer +{ +public: + + InitDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&, const Slice::UnitPtr&, const Slice::UnitPtr&); + + virtual void initialize(const DataFactoryPtr&, const DataPtr&, const Ice::CommunicatorPtr&); + + std::string typeName() const; + +private: + + Slice::UnitPtr _old; + Slice::UnitPtr _new; + Slice::TypePtr _type; +}; +typedef IceUtil::Handle<InitDescriptor> InitDescriptorPtr; + +class RecordDescriptor : public ExecutableContainerDescriptor +{ +public: + + RecordDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&, const Slice::UnitPtr&, const Slice::UnitPtr&); + + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + void transformRecord(IceInternal::BasicStream&, IceInternal::BasicStream&, IceInternal::BasicStream&, + IceInternal::BasicStream&, TransformInfo*); + + Slice::UnitPtr _old; + Slice::UnitPtr _new; +}; +typedef IceUtil::Handle<RecordDescriptor> RecordDescriptorPtr; + +class DatabaseDescriptor : public ExecutableContainerDescriptor +{ +public: + + DatabaseDescriptor(const DescriptorPtr&, int, const DataFactoryPtr&, const ErrorReporterPtr&, + const IceXML::Attributes&, const Slice::UnitPtr&, const Slice::UnitPtr&); + + virtual void addChild(const DescriptorPtr&); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + +private: + + Slice::UnitPtr _old; + Slice::UnitPtr _new; + Slice::TypePtr _oldKey; + Slice::TypePtr _newKey; + Slice::TypePtr _oldValue; + Slice::TypePtr _newValue; + RecordDescriptorPtr _record; +}; +typedef IceUtil::Handle<DatabaseDescriptor> DatabaseDescriptorPtr; + +class TransformInfoI; + +class TransformDBDescriptor : public Descriptor +{ +public: + + TransformDBDescriptor(int, const DataFactoryPtr&, const ErrorReporterPtr&, const IceXML::Attributes&, + const Slice::UnitPtr&, const Slice::UnitPtr&); + ~TransformDBDescriptor(); + + virtual void addChild(const DescriptorPtr&); + virtual void validate(); + virtual void execute(const SymbolTablePtr&, TransformInfo*); + + void transform(const Ice::CommunicatorPtr&, Db*, DbTxn*, Db*, DbTxn*, bool); + +private: + + Slice::UnitPtr _old; + Slice::UnitPtr _new; + DatabaseDescriptorPtr _database; + std::vector<DescriptorPtr> _children; + TransformInfoI* _info; +}; +typedef IceUtil::Handle<TransformDBDescriptor> TransformDBDescriptorPtr; + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/TransformVisitor.cpp b/cpp/src/FreezeScript/TransformVisitor.cpp new file mode 100644 index 00000000000..864b46dc66a --- /dev/null +++ b/cpp/src/FreezeScript/TransformVisitor.cpp @@ -0,0 +1,901 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/TransformVisitor.h> +#include <FreezeScript/Util.h> + +using namespace std; + +FreezeScript::TransformVisitor::TransformVisitor(const DataPtr& src, const DataFactoryPtr& factory, + const ErrorReporterPtr& errorReporter, TransformInfo* info, + const string& context) : + _src(src), _factory(factory), _errorReporter(errorReporter), _info(info), _context(context) +{ + assert(_info != 0); +} + +void +FreezeScript::TransformVisitor::visitBoolean(const BooleanDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + BooleanDataPtr b = BooleanDataPtr::dynamicCast(_src); + if(b) + { + dest->setValue(b->getValue()); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + string v = s->getValue(); + if(v == "true") + { + dest->setValue(true); + } + else if(v == "false") + { + dest->setValue(false); + } + else + { + conversionError(type, _src->getType(), v); + } + } + else + { + typeMismatchError(type, _src->getType()); + } + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitInteger(const IntegerDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + IntegerDataPtr i = IntegerDataPtr::dynamicCast(_src); + if(i) + { + dest->setValue(i->getValue(), false); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + string str = s->getValue(); + string::size_type pos; + Ice::Long value; + if(IceUtil::stringToInt64(str, value, pos)) + { + dest->setValue(value, false); + } + else + { + conversionError(type, _src->getType(), str); + } + } + else + { + typeMismatchError(type, _src->getType()); + } + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitDouble(const DoubleDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + DoubleDataPtr d = DoubleDataPtr::dynamicCast(_src); + if(d) + { + dest->setValue(d->doubleValue()); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + string str = s->stringValue(); + const char* start = str.c_str(); + char* end; + double v = strtod(start, &end); + if(errno == ERANGE) + { + rangeError(str, type); + } + else + { + while(*end) + { + if(!isspace(*end)) + { + conversionError(type, _src->getType(), str); + return; + } + end++; + } + if(!*end) + { + dest->setValue(v); + } + } + } + else + { + typeMismatchError(type, _src->getType()); + } + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitString(const StringDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + BooleanDataPtr b = BooleanDataPtr::dynamicCast(_src); + IntegerDataPtr i = IntegerDataPtr::dynamicCast(_src); + DoubleDataPtr d = DoubleDataPtr::dynamicCast(_src); + EnumDataPtr e = EnumDataPtr::dynamicCast(_src); + ProxyDataPtr p = ProxyDataPtr::dynamicCast(_src); + if(s || b || i || d || e || p) + { + dest->setValue(_src->toString()); + } + else + { + typeMismatchError(type, _src->getType()); + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitProxy(const ProxyDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + ProxyDataPtr p = ProxyDataPtr::dynamicCast(_src); + if(p) + { + dest->setValue(p->getValue()); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + dest->setValue(s->getValue(), false); + } + else + { + typeMismatchError(type, _src->getType()); + } + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitStruct(const StructDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + StructDataPtr s = StructDataPtr::dynamicCast(_src); + if(s && isCompatible(type, _src->getType())) + { + // + // Transform members with the same name. + // + DataMemberMap srcMap = s->getMembers(); + DataMemberMap destMap = dest->getMembers(); + string typeName = typeToString(type); + for(DataMemberMap::iterator p = destMap.begin(); p != destMap.end(); ++p) + { + DataMemberMap::iterator q = srcMap.find(p->first); + if(q != srcMap.end()) + { + string context = typeName + " member " + p->first + " value"; + TransformVisitor v(q->second, _factory, _errorReporter, _info, context); + p->second->visit(v); + } + } + } + else + { + typeMismatchError(type, _src->getType()); + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitSequence(const SequenceDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + SequenceDataPtr s = SequenceDataPtr::dynamicCast(_src); + if(s && isCompatible(type, _src->getType())) + { + DataList& srcElements = s->getElements(); + DataList destElements; + Slice::SequencePtr seqType = Slice::SequencePtr::dynamicCast(type); + assert(seqType); + Slice::TypePtr elemType = seqType->type(); + string typeName = typeToString(type); + for(DataList::const_iterator p = srcElements.begin(); p != srcElements.end(); ++p) + { + DataPtr element = _factory->create(elemType, false); + Destroyer<DataPtr> elementDestroyer(element); + try + { + TransformVisitor v(*p, _factory, _errorReporter, _info, typeName + " element"); + element->visit(v); + destElements.push_back(element); + elementDestroyer.release(); + } + catch(const ClassNotFoundException& ex) + { + // + // If transformation of the sequence element fails because a class + // could not be found, then we invoke purgeObjects() to determine + // whether we should ignore the situation (and remove the element + // from the sequence) or raise the exception again. + // + if(!_info->purgeObjects()) + { + throw; + } + warning("purging element of sequence " + typeToString(type) + + " due to missing class type " + ex.id); + } + } + DataList& l = dest->getElements(); + l.swap(destElements); + } + else + { + typeMismatchError(type, _src->getType()); + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitEnum(const EnumDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + string name; + EnumDataPtr e = EnumDataPtr::dynamicCast(_src); + if(e && isCompatible(type, _src->getType())) + { + name = e->toString(); + } + else + { + StringDataPtr s = StringDataPtr::dynamicCast(_src); + if(s) + { + name = s->getValue(); + } + else + { + typeMismatchError(type, _src->getType()); + return; + } + } + + if(!dest->setValueAsString(name)) + { + conversionError(type, _src->getType(), name); + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitDictionary(const DictionaryDataPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + if(_info->doDefaultTransform(type)) + { + DictionaryDataPtr d = DictionaryDataPtr::dynamicCast(_src); + if(d && isCompatible(type, _src->getType())) + { + DataMap& srcMap = d->getElements(); + DataMap destMap; + Slice::DictionaryPtr dictType = Slice::DictionaryPtr::dynamicCast(type); + assert(dictType); + Slice::TypePtr keyType = dictType->keyType(); + Slice::TypePtr valueType = dictType->valueType(); + string typeName = typeToString(type); + for(DataMap::const_iterator p = srcMap.begin(); p != srcMap.end(); ++p) + { + DataPtr key = _factory->create(keyType, false); + Destroyer<DataPtr> keyDestroyer(key); + DataPtr value = _factory->create(valueType, false); + Destroyer<DataPtr> valueDestroyer(value); + + TransformVisitor keyVisitor(p->first, _factory, _errorReporter, _info, typeName + " key"); + key->visit(keyVisitor); + + try + { + TransformVisitor valueVisitor(p->second, _factory, _errorReporter, _info, typeName + " value"); + value->visit(valueVisitor); + } + catch(const ClassNotFoundException& ex) + { + // + // If transformation of the dictionary value fails because a class + // could not be found, then we invoke purgeObjects() to determine + // whether we should ignore the situation (and remove the element + // from the dictionary) or raise the exception again. + // + if(!_info->purgeObjects()) + { + throw; + } + warning("purging element of dictionary " + typeToString(dictType) + " due to missing class type " + + ex.id); + continue; + } + + DataMap::const_iterator q = destMap.find(key); + if(q != destMap.end()) + { + warning("duplicate dictionary key in " + typeToString(dictType)); + } + else + { + destMap.insert(DataMap::value_type(key, value)); + keyDestroyer.release(); + valueDestroyer.release(); + } + } + DataMap& m = dest->getElements(); + m.swap(destMap); + } + else + { + typeMismatchError(type, _src->getType()); + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::visitObject(const ObjectRefPtr& dest) +{ + Slice::TypePtr type = dest->getType(); + ObjectRefPtr src = ObjectRefPtr::dynamicCast(_src); + if(!src) + { + typeMismatchError(type, _src->getType()); + } + else if(_info->doDefaultTransform(type)) + { + ObjectDataPtr srcValue = src->getValue(); + Slice::TypePtr srcType = src->getType(); + if(!srcValue) + { + // + // Allow a nil value from type Object. + // + if(Slice::BuiltinPtr::dynamicCast(srcType) || isCompatible(type, srcType)) + { + dest->setValue(0); + } + else + { + typeMismatchError(type, srcType); + } + } + else + { + Slice::TypePtr srcValueType = srcValue->getType(); + if(isCompatible(type, srcValueType)) + { + // + // 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() == srcValueType->unit().get()) + { + dest->setValue(srcValue); + } + else + { + ObjectDataMap& objectDataMap = _info->getObjectDataMap(); + ObjectDataMap::iterator p = objectDataMap.find(srcValue.get()); + if(p != objectDataMap.end() && p->second) + { + dest->setValue(p->second); + } + else + { + // + // If the type has been renamed, we need to get its equivalent + // in the new Slice definitions. + // + Slice::TypePtr newType = _info->getRenamedType(srcValueType); + if(!newType) + { + string name = typeToString(srcValueType); + Slice::TypeList l = type->unit()->lookupType(name, false); + if(l.empty()) + { + throw ClassNotFoundException(name); + } + newType = l.front(); + } + + // + // Use createObject() so that an initializer is invoked if necessary. + // + DataPtr newObj = _factory->createObject(newType, false); + ObjectRefPtr newRef = ObjectRefPtr::dynamicCast(newObj); + assert(newRef); + + ObjectDataPtr newValue = newRef->getValue(); + try + { + transformObject(newValue, srcValue); + } + catch(...) + { + newObj->destroy(); + throw; + } + + dest->setValue(newValue); + newObj->destroy(); + } + } + } + else + { + typeMismatchError(type, srcValueType); + } + } + } + _info->executeCustomTransform(dest, _src); +} + +void +FreezeScript::TransformVisitor::transformObject(const ObjectDataPtr& dest, const ObjectDataPtr& src) +{ + // + // 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& objectDataMap = _info->getObjectDataMap(); + ObjectDataMap::iterator p = objectDataMap.find(src.get()); + assert(p != objectDataMap.end()); + assert(p->second == 0); + objectDataMap.erase(p); + objectDataMap.insert(ObjectDataMap::value_type(src.get(), dest)); + + try + { + // + // Transform members with the same name. + // + DataMemberMap srcMap = src->getMembers(); + DataMemberMap destMap = dest->getMembers(); + string typeName = typeToString(dest->getType()); + for(DataMemberMap::iterator p = destMap.begin(); p != destMap.end(); ++p) + { + DataMemberMap::iterator q = srcMap.find(p->first); + if(q != srcMap.end()) + { + string context = typeName + " member " + p->first + " value"; + TransformVisitor v(q->second, _factory, _errorReporter, _info, context); + p->second->visit(v); + } + } + } + catch(...) + { + objectDataMap.erase(p); + objectDataMap.insert(ObjectDataMap::value_type(src.get(), 0)); + throw; + } +} + +bool +FreezeScript::TransformVisitor::checkRename(const Slice::TypePtr& dest, const Slice::TypePtr& src) +{ + if(dest->unit().get() != src->unit().get()) + { + Slice::TypePtr t = _info->getRenamedType(src); + return t.get() == dest.get(); + } + + return false; +} + +bool +FreezeScript::TransformVisitor::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) + { + if(checkRename(dest, src)) + { + return true; + } + + 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::BuiltinPtr b2 = Slice::BuiltinPtr::dynamicCast(src); + if(b2 && b2->kind() == Slice::Builtin::KindString) + { + return true; + } + + if(checkRename(dest, src)) + { + return true; + } + + Slice::EnumPtr e2 = Slice::EnumPtr::dynamicCast(src); + if(e2 && e1->scoped() == e2->scoped()) + { + return true; + } + + return false; + } + + assert(false); + return false; +} + +bool +FreezeScript::TransformVisitor::checkClasses(const Slice::ClassDeclPtr& dest, const Slice::ClassDeclPtr& src) +{ + // + // Here are the rules for verifying class compatibility: + // + // 1. If the type ids are the same, assume they are compatible. + // 2. If the source type has been renamed, then check its equivalent new definition for compatibility. + // 3. Otherwise, the types are only compatible if they are defined in the same Slice unit, and if the + // destination type is a base type of the source type. + // + string s1 = dest->scoped(); + string s2 = src->scoped(); + if(s1 == s2) + { + return true; + } + else + { + Slice::TypePtr t = _info->getRenamedType(src); + Slice::ClassDeclPtr s = Slice::ClassDeclPtr::dynamicCast(t); + if(s) + { + return checkClasses(dest, s); + } + + if(dest->unit().get() != src->unit().get()) + { + Slice::TypeList l = dest->unit()->lookupTypeNoBuiltin(s2, false); + if(l.empty()) + { + _errorReporter->error("class " + s2 + " not found in new Slice definitions"); + } + s = Slice::ClassDeclPtr::dynamicCast(l.front()); + } + else + { + s = src; + } + + if(s) + { + Slice::ClassDefPtr def = s->definition(); + if(!def) + { + _errorReporter->error("class " + s2 + " declared but not defined"); + } + return def->isA(s1); + } + } + + return false; +} + +void +FreezeScript::TransformVisitor::typeMismatchError(const Slice::TypePtr& dest, const Slice::TypePtr& src) +{ + ostringstream ostr; + ostr << "unable to transform"; + if(!_context.empty()) + { + ostr << ' ' << _context; + } + ostr << " from " << typeToString(src) << " to " << typeToString(dest); + warning(ostr.str()); +} + +void +FreezeScript::TransformVisitor::conversionError(const Slice::TypePtr& dest, const Slice::TypePtr& src, + const string& value) +{ + ostringstream ostr; + ostr << "unable to convert"; + if(!_context.empty()) + { + ostr << ' ' << _context; + } + ostr << " `" << value << "' from " << typeToString(src) << " to " << typeToString(dest); + warning(ostr.str()); +} + +void +FreezeScript::TransformVisitor::rangeError(const string& value, const Slice::TypePtr& type) +{ + ostringstream ostr; + if(!_context.empty()) + { + ostr << _context << ' '; + } + ostr << "`" << value << "' is out of range for type " << typeToString(type); + warning(ostr.str()); +} + +void +FreezeScript::TransformVisitor::warning(const string& msg) +{ + _errorReporter->warning(msg); +} diff --git a/cpp/src/FreezeScript/TransformVisitor.h b/cpp/src/FreezeScript/TransformVisitor.h new file mode 100644 index 00000000000..6abf97509d6 --- /dev/null +++ b/cpp/src/FreezeScript/TransformVisitor.h @@ -0,0 +1,112 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_TRANSFORM_VISITOR_H +#define FREEZE_SCRIPT_TRANSFORM_VISITOR_H + +#include <FreezeScript/Data.h> + +namespace FreezeScript +{ + +// +// ObjectDataMap associates old instances of ObjectData to their +// transformed equivalents. +// +typedef std::map<const ObjectData*, ObjectDataPtr> ObjectDataMap; + +// +// TransformInfo supplies information required by TransformVisitor. +// +class TransformInfo +{ +public: + + virtual ~TransformInfo() {} + + // + // Indicates whether the default transformation should be performed. + // + virtual bool doDefaultTransform(const Slice::TypePtr&) = 0; + + // + // Indicates whether a base class transformation should be performed. + // + virtual bool doBaseTransform(const Slice::ClassDefPtr&) = 0; + + // + // Given an old type, return the equivalent new type if the type + // has been renamed. + // + virtual Slice::TypePtr getRenamedType(const Slice::TypePtr&) = 0; + + // + // Execute the custom transformation for the given old and new Data values. + // + virtual void executeCustomTransform(const DataPtr&, const DataPtr&) = 0; + + // + // Indicates whether objects should be removed if no class definition is found. + // + virtual bool purgeObjects() = 0; + + // + // Associates old object instances with their transformed equivalents. + // + virtual ObjectDataMap& getObjectDataMap() = 0; +}; + +// +// TransformVisitor is used to visit a destination Data value and +// preserve as much information as possible from the source Data value. +// +class TransformVisitor : public DataVisitor +{ +public: + + TransformVisitor(const DataPtr&, const DataFactoryPtr&, const ErrorReporterPtr&, TransformInfo*, + const std::string& = std::string()); + + virtual void visitBoolean(const BooleanDataPtr&); + virtual void visitInteger(const IntegerDataPtr&); + virtual void visitDouble(const DoubleDataPtr&); + virtual void visitString(const StringDataPtr&); + virtual void visitProxy(const ProxyDataPtr&); + virtual void visitStruct(const StructDataPtr&); + virtual void visitSequence(const SequenceDataPtr&); + virtual void visitEnum(const EnumDataPtr&); + virtual void visitDictionary(const DictionaryDataPtr&); + virtual void visitObject(const ObjectRefPtr&); + +private: + + void transformObject(const ObjectDataPtr&, const ObjectDataPtr&); + bool checkRename(const Slice::TypePtr&, const Slice::TypePtr&); + bool isCompatible(const Slice::TypePtr&, const Slice::TypePtr&); + bool checkClasses(const Slice::ClassDeclPtr&, const Slice::ClassDeclPtr&); + void typeMismatchError(const Slice::TypePtr&, const Slice::TypePtr&); + void conversionError(const Slice::TypePtr&, const Slice::TypePtr&, const std::string&); + void rangeError(const std::string&, const Slice::TypePtr&); + void warning(const std::string&); + + DataPtr _src; + DataFactoryPtr _factory; + ErrorReporterPtr _errorReporter; + TransformInfo* _info; + std::string _context; // Provides additional detail for use in warning messages. +}; + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Transformer.cpp b/cpp/src/FreezeScript/Transformer.cpp new file mode 100644 index 00000000000..01a1c7519f1 --- /dev/null +++ b/cpp/src/FreezeScript/Transformer.cpp @@ -0,0 +1,310 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Transformer.h> +#include <FreezeScript/TransformDescriptors.h> +#include <FreezeScript/Exception.h> +#include <FreezeScript/TransformAnalyzer.h> +#include <FreezeScript/Util.h> +#include <db_cxx.h> + +using namespace std; + +namespace FreezeScript +{ + +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); + + TransformDBDescriptorPtr descriptor() const; + +private: + + DataFactoryPtr _factory; + Slice::UnitPtr _old; + Slice::UnitPtr _new; + ErrorReporterPtr _errorReporter; + DescriptorPtr _current; + TransformDBDescriptorPtr _descriptor; +}; + +} // End of namespace FreezeScript + +// +// DescriptorHandler +// +FreezeScript::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 +FreezeScript::DescriptorHandler::startElement(const string& name, const IceXML::Attributes& attributes, int line, + int column) +{ + DescriptorPtr d; + + if(name == "transformdb") + { + if(_current) + { + _errorReporter->descriptorError("<transformdb> must be the top-level element", line); + } + + _descriptor = new TransformDBDescriptor(line, _factory, _errorReporter, attributes, _old, _new); + d = _descriptor; + } + else if(name == "database") + { + if(!_current) + { + _errorReporter->descriptorError("<database> must be a child of <transformdb>", line); + } + + d = new DatabaseDescriptor(_current, line, _factory, _errorReporter, attributes, _old, _new); + } + else if(name == "record") + { + if(!_current) + { + _errorReporter->descriptorError("<record> must be a child of <database>", line); + } + + d = new RecordDescriptor(_current, line, _factory, _errorReporter, attributes, _old, _new); + } + else if(name == "transform") + { + if(!_current) + { + _errorReporter->descriptorError("<transform> must be a child of <transformdb>", line); + } + + d = new TransformDescriptor(_current, line, _factory, _errorReporter, attributes, _old, _new); + } + else if(name == "init") + { + if(!_current) + { + _errorReporter->descriptorError("<init> must be a child of <transformdb>", line); + } + + d = new InitDescriptor(_current, line, _factory, _errorReporter, attributes, _old, _new); + } + else if(name == "set") + { + if(!_current) + { + _errorReporter->descriptorError("<set> cannot be a top-level element", line); + } + + d = new SetDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "define") + { + if(!_current) + { + _errorReporter->descriptorError("<define> cannot be a top-level element", line); + } + + d = new DefineDescriptor(_current, line, _factory, _errorReporter, attributes, _old, _new); + } + else if(name == "add") + { + if(!_current) + { + _errorReporter->descriptorError("<add> cannot be a top-level element", line); + } + + d = new AddDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "remove") + { + if(!_current) + { + _errorReporter->descriptorError("<remove> cannot be a top-level element", line); + } + + d = new RemoveDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "delete") + { + if(!_current) + { + _errorReporter->descriptorError("<delete> cannot be a top-level element", line); + } + + d = new DeleteDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "fail") + { + if(!_current) + { + _errorReporter->descriptorError("<fail> cannot be a top-level element", line); + } + + d = new FailDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "echo") + { + if(!_current) + { + _errorReporter->descriptorError("<echo> cannot be a top-level element", line); + } + + d = new EchoDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "if") + { + if(!_current) + { + _errorReporter->descriptorError("<if> cannot be a top-level element", line); + } + + d = new IfDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else if(name == "iterate") + { + if(!_current) + { + _errorReporter->descriptorError("<iterate> cannot be a top-level element", line); + } + + d = new IterateDescriptor(_current, line, _factory, _errorReporter, attributes); + } + else + { + _errorReporter->descriptorError("unknown descriptor `" + name + "'", line); + } + + if(_current) + { + _current->addChild(d); + } + _current = d; +} + +void +FreezeScript::DescriptorHandler::endElement(const std::string& name, int, int) +{ + assert(_current); + _current = _current->parent(); +} + +void +FreezeScript::DescriptorHandler::characters(const std::string&, int, int) +{ +} + +void +FreezeScript::DescriptorHandler::error(const std::string& msg, int line, int col) +{ + _errorReporter->descriptorError(msg, line); +} + +FreezeScript::TransformDBDescriptorPtr +FreezeScript::DescriptorHandler::descriptor() const +{ + return _descriptor; +} + +// +// Transformer +// +FreezeScript::Transformer::Transformer(const Ice::CommunicatorPtr& communicator, const Slice::UnitPtr& oldUnit, + const Slice::UnitPtr& newUnit, bool ignoreTypeChanges, bool purgeObjects) : + _communicator(communicator), _old(oldUnit), _new(newUnit), _ignoreTypeChanges(ignoreTypeChanges), + _purgeObjects(purgeObjects) +{ + createCoreSliceTypes(_old); + createCoreSliceTypes(_new); + + createEvictorSliceTypes(_old); + createEvictorSliceTypes(_new); +} + +void +FreezeScript::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; + } + + TransformAnalyzer analyzer(_old, _new, _ignoreTypeChanges); + analyzer.analyze(oldKeyType, newKeyType, oldValueType, newValueType, descriptors, missingTypes, errors); +} + +void +FreezeScript::Transformer::analyze(ostream& descriptors, Ice::StringSeq& missingTypes, Ice::StringSeq& errors) +{ + const string keyType = "::Freeze::EvictorStorageKey"; + const string valueType = "::Freeze::ObjectRecord"; + analyze(keyType, keyType, valueType, valueType, descriptors, missingTypes, errors); +} + +void +FreezeScript::Transformer::transform(istream& is, Db* db, DbTxn* txn, Db* dbNew, DbTxn* txnNew, ostream& errors, + bool suppress) +{ + ErrorReporterPtr errorReporter = new ErrorReporter(errors, suppress); + + try + { + DataFactoryPtr factory = new DataFactory(_communicator, _new, errorReporter); + DescriptorHandler dh(factory, _old, _new, errorReporter); + IceXML::Parser::parse(is, dh); + + TransformDBDescriptorPtr descriptor = dh.descriptor(); + descriptor->validate(); + descriptor->transform(_communicator, db, txn, dbNew, txnNew, _purgeObjects); + } + catch(const IceXML::ParserException& ex) + { + errorReporter->error(ex.reason()); + } +} + +Slice::TypePtr +FreezeScript::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(); +} diff --git a/cpp/src/FreezeScript/Transformer.h b/cpp/src/FreezeScript/Transformer.h new file mode 100644 index 00000000000..1bdaa56fc81 --- /dev/null +++ b/cpp/src/FreezeScript/Transformer.h @@ -0,0 +1,54 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_TRANSFORMER_H +#define FREEZE_SCRIPT_TRANSFORMER_H + +#include <Ice/Ice.h> +#include <Slice/Parser.h> +#include <FreezeScript/Exception.h> + +class Db; +class DbTxn; + +namespace FreezeScript +{ + +class Transformer +{ +public: + + Transformer(const Ice::CommunicatorPtr&, const Slice::UnitPtr&, const Slice::UnitPtr&, bool, bool); + + void analyze(const std::string&, const std::string&, const std::string&, const std::string&, std::ostream&, + Ice::StringSeq&, Ice::StringSeq&); + + void analyze(std::ostream&, Ice::StringSeq&, Ice::StringSeq&); + + void transform(std::istream&, Db*, DbTxn*, Db*, DbTxn*, std::ostream&, bool); + +private: + + static Slice::TypePtr findType(const Slice::UnitPtr&, const std::string&, Ice::StringSeq&); + + Ice::CommunicatorPtr _communicator; + Slice::UnitPtr _old; + Slice::UnitPtr _new; + bool _ignoreTypeChanges; + bool _purgeObjects; +}; + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/Util.cpp b/cpp/src/FreezeScript/Util.cpp new file mode 100644 index 00000000000..9012bf63cea --- /dev/null +++ b/cpp/src/FreezeScript/Util.cpp @@ -0,0 +1,273 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Util.h> +#include <FreezeScript/Exception.h> +#include <Slice/Preprocessor.h> + +using namespace std; +using namespace Slice; + +string +FreezeScript::typeToString(const TypePtr& type) +{ + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + ContainedPtr c = ContainedPtr::dynamicCast(type); + ProxyPtr p = ProxyPtr::dynamicCast(type); + if(b) + { + return b->kindAsString(); + } + else if(c) + { + return c->scoped(); + } + else + { + ProxyPtr p = ProxyPtr::dynamicCast(type); + assert(p); + return p->_class()->scoped() + "*"; + } +} + +bool +FreezeScript::ignoreType(const string& type) +{ + // + // Suppress descriptors for the following pre-defined types. Must be kept in ascending alphabetical order. + // + static const string ignoreTypeList[] = + { + "::Freeze::EvictorStorageKey", + "::Freeze::ObjectRecord", + "::Freeze::Statistics", + "::Ice::FacetPath", + "::Ice::Identity", + "::_FacetMap" + }; + + return binary_search(&ignoreTypeList[0], &ignoreTypeList[sizeof(ignoreTypeList) / sizeof(*ignoreTypeList)], type); +} + +void +FreezeScript::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 +FreezeScript::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 Exception(__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 Exception(__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 Exception(__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 Exception(__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 Exception(__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 Exception(__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 Exception(__FILE__, __LINE__, "the symbol `::Freeze::ObjectRecord' is defined in " + "Slice but is not a struct"); + } + } +} + +bool +FreezeScript::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) + { + 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; +} diff --git a/cpp/src/FreezeScript/Util.h b/cpp/src/FreezeScript/Util.h new file mode 100644 index 00000000000..e180c775e1f --- /dev/null +++ b/cpp/src/FreezeScript/Util.h @@ -0,0 +1,66 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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_SCRIPT_UTIL_H +#define FREEZE_SCRIPT_UTIL_H + +#include <Slice/Parser.h> + +namespace FreezeScript +{ + +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; + } + + void release() + { + _p = 0; + } + +private: + + T _p; +}; + +std::string typeName(const Slice::TypePtr&); +std::string typeToString(const Slice::TypePtr&); +bool ignoreType(const std::string&); +void createCoreSliceTypes(const Slice::UnitPtr&); +void createEvictorSliceTypes(const Slice::UnitPtr&); +bool parseSlice(const std::string&, const Slice::UnitPtr&, const std::vector<std::string>&, const std::string&, bool); + +} // End of namespace FreezeScript + +#endif diff --git a/cpp/src/FreezeScript/transformdb.cpp b/cpp/src/FreezeScript/transformdb.cpp new file mode 100644 index 00000000000..b85365a8cb7 --- /dev/null +++ b/cpp/src/FreezeScript/transformdb.cpp @@ -0,0 +1,645 @@ +// ********************************************************************** +// +// Copyright (c) 2004 +// 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 <FreezeScript/Transformer.h> +#include <FreezeScript/Util.h> +#include <db_cxx.h> +#include <sys/stat.h> +#include <fstream> +#include <algorithm> + +using namespace std; + +#ifdef _WIN32 +# define FREEZE_SCRIPT_DB_MODE 0 +#else +# define FREEZE_SCRIPT_DB_MODE (S_IRUSR | S_IWUSR) +#endif + +static void +usage(const char* n) +{ + cerr << "Usage: " << n << " [options] [dbenv db newdbenv]\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" + "-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" + "-p Purge objects whose types no longer exist.\n" + "-c Use catastrophic recovery on the old database environment.\n" + "-w Suppress duplicate warnings during transformation.\n" + "-f FILE Execute the transformation descriptors in the file FILE.\n" + "--include-old DIR Put DIR in the include file search path for old Slice\n" + " definitions.\n" + "--include-new DIR Put DIR in the include file search path for new Slice\n" + " definitions.\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 int +run(int argc, char** argv, const Ice::CommunicatorPtr& communicator) +{ + string oldCppArgs; + string newCppArgs; + bool debug = false; + bool ice = true; // Needs to be true in order to create default definitions. + bool caseSensitive = false; + string outputFile; + bool ignoreTypeChanges = false; + bool purgeObjects = false; + bool catastrophicRecover = false; + bool suppress = false; + string inputFile; + vector<string> oldSlice; + vector<string> newSlice; + bool evictor = false; + string keyTypeNames; + string valueTypeNames; + string dbEnvName, dbName, dbEnvNameNew; + + 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) + { + oldCppArgs += ' '; + oldCppArgs += argv[idx]; + newCppArgs += ' '; + newCppArgs += argv[idx]; + + 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], "-p") == 0) + { + purgeObjects = true; + for(int i = idx ; i + 1 < argc ; ++i) + { + argv[i] = argv[i + 1]; + } + --argc; + } + else if(strcmp(argv[idx], "-c") == 0) + { + catastrophicRecover = true; + for(int i = idx ; i + 1 < argc ; ++i) + { + argv[i] = argv[i + 1]; + } + --argc; + } + else if(strcmp(argv[idx], "-w") == 0) + { + suppress = 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], "--include-old") == 0) + { + oldCppArgs += " -I"; + oldCppArgs += argv[idx + 1]; + + for(int i = idx ; i + 2 < argc ; ++i) + { + argv[i] = argv[i + 2]; + } + argc -= 2; + } + else if(strcmp(argv[idx], "--include-new") == 0) + { + newCppArgs += " -I"; + newCppArgs += 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) + { + dbEnvNameNew = argv[3]; + } + + Slice::UnitPtr oldUnit = Slice::Unit::createUnit(true, true, ice, caseSensitive); + FreezeScript::Destroyer<Slice::UnitPtr> oldD(oldUnit); + if(!FreezeScript::parseSlice(argv[0], oldUnit, oldSlice, oldCppArgs, debug)) + { + return EXIT_FAILURE; + } + + Slice::UnitPtr newUnit = Slice::Unit::createUnit(true, true, ice, caseSensitive); + FreezeScript::Destroyer<Slice::UnitPtr> newD(newUnit); + if(!FreezeScript::parseSlice(argv[0], newUnit, newSlice, newCppArgs, debug)) + { + return EXIT_FAILURE; + } + + // + // Create the Transformer. + // + FreezeScript::Transformer transformer(communicator, oldUnit, newUnit, ignoreTypeChanges, purgeObjects); + + // + // 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(); + } + + if(dbEnvName == dbEnvNameNew) + { + cerr << argv[0] << ": database environment names must be different" << endl; + return EXIT_FAILURE; + } + + DbEnv dbEnv(0); + DbEnv dbEnvNew(0); + DbTxn* txn = 0; + DbTxn* txnNew = 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); + dbEnvNew.set_alloc(::malloc, ::realloc, ::free); +#endif + + // + // Open the old database environment. Use DB_RECOVER_FATAL if -c is specified. + // + { + u_int32_t flags = DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_CREATE; + if(catastrophicRecover) + { + flags |= DB_RECOVER_FATAL; + } + else + { + flags |= DB_RECOVER; + } + dbEnv.open(dbEnvName.c_str(), flags, FREEZE_SCRIPT_DB_MODE); + } + + // + // Open the new database environment. + // + { + u_int32_t flags = DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_CREATE; + dbEnvNew.open(dbEnvNameNew.c_str(), flags, FREEZE_SCRIPT_DB_MODE); + } + + // + // Open the old database in a transaction. + // + db = new Db(&dbEnv, 0); + dbEnv.txn_begin(0, &txn, 0); + db->open(txn, dbName.c_str(), 0, DB_BTREE, DB_RDONLY, FREEZE_SCRIPT_DB_MODE); + + // + // Open the new database in a transaction. + // + dbNew = new Db(&dbEnvNew, 0); + dbEnvNew.txn_begin(0, &txnNew, 0); + dbNew->open(txnNew, dbName.c_str(), 0, DB_BTREE, DB_CREATE | DB_EXCL, FREEZE_SCRIPT_DB_MODE); + + istringstream istr(descriptors); + transformer.transform(istr, db, txn, dbNew, txnNew, cerr, suppress); + + // + // Checkpoint to migrate changes from the log to the database. + // + dbEnvNew.txn_checkpoint(0, 0, DB_FORCE); + } + catch(const DbException& ex) + { + cerr << argv[0] << ": database error: " << ex.what() << endl; + status = EXIT_FAILURE; + } + catch(...) + { + if(txn) + { + txn->abort(); + } + if(db) + { + db->close(0); + delete db; + } + if(txnNew) + { + txnNew->abort(); + } + if(dbNew) + { + dbNew->close(0); + delete dbNew; + } + dbEnv.close(0); + dbEnvNew.close(0); + throw; + } + + if(txn) + { + txn->abort(); + } + if(db) + { + db->close(0); + delete db; + } + if(txnNew) + { + if(status == EXIT_FAILURE) + { + txnNew->abort(); + } + else + { + txnNew->commit(0); + } + } + if(dbNew) + { + dbNew->close(0); + delete dbNew; + } + dbEnv.close(0); + dbEnvNew.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 FreezeScript::Exception& ex) + { + string reason = ex.reason(); + cerr << argv[0] << ": " << reason; + if(reason[reason.size() - 1] != '\n') + { + cerr << endl; + } + 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/FreezeScript/transformdb.dsp b/cpp/src/FreezeScript/transformdb.dsp new file mode 100644 index 00000000000..9bbfbac1ba2 --- /dev/null +++ b/cpp/src/FreezeScript/transformdb.dsp @@ -0,0 +1,304 @@ +# Microsoft Developer Studio Project File - Name="TransformDB" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=TransformDB - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "TransformDB.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "TransformDB.mak" CFG="TransformDB - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "TransformDB - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "TransformDB - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "TransformDB - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /WX /GR /GX /O2 /I ".." /I "../../include" /I "dummyinclude" /D "NDEBUG" /D "_CONSOLE" /FD /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 libdb41.lib setargv.obj /nologo /subsystem:console /machine:I386 /out:"Release/transformdb.exe" /libpath:"../../../lib"
+# SUBTRACT LINK32 /debug /nodefaultlib
+# Begin Special Build Tool
+OutDir=.\Release
+TargetName=transformdb
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy $(OutDir)\$(TargetName).exe ..\..\bin
+# End Special Build Tool
+
+!ELSEIF "$(CFG)" == "TransformDB - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /WX /Gm /GR /GX /Zi /Od /I ".." /I "../../include" /I "dummyinclude" /D "_DEBUG" /D "_CONSOLE" /FD /GZ /c
+# SUBTRACT CPP /Fr /YX
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 libdb41d.lib setargv.obj /nologo /subsystem:console /debug /machine:I386 /out:"Debug/transformdb.exe" /pdbtype:sept /libpath:"../../../lib"
+# SUBTRACT LINK32 /nodefaultlib
+# Begin Special Build Tool
+OutDir=.\Debug
+TargetName=transformdb
+SOURCE="$(InputPath)"
+PostBuild_Cmds=copy $(OutDir)\$(TargetName).exe ..\..\bin
+# End Special Build Tool
+
+!ENDIF
+
+# Begin Target
+
+# Name "TransformDB - Win32 Release"
+# Name "TransformDB - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\AssignVisitor.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Data.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Error.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Exception.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Functions.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Grammar.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Parser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Print.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Scanner.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformAnalyzer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformDB.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformDescriptors.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformVisitor.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Transformer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Util.cpp
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\AssignVisitor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Data.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Error.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Exception.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Functions.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\GrammarUtil.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Grammar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Parser.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Print.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformAnalyzer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformDescriptors.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\TransformVisitor.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Transformer.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Util.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# Begin Source File
+
+SOURCE=.\Grammar.y
+
+!IF "$(CFG)" == "Transform - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\Grammar.y
+
+BuildCmds= \
+ bison -dvt Grammar.y \
+ move Grammar.tab.c Grammar.cpp \
+ move Grammar.tab.h Grammar.h \
+
+
+"Grammar.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"Grammar.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Transform - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\Grammar.y
+
+BuildCmds= \
+ bison -dvt Grammar.y \
+ move Grammar.tab.c Grammar.cpp \
+ move Grammar.tab.h Grammar.h \
+
+
+"Grammar.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"Grammar.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=.\Scanner.l
+
+!IF "$(CFG)" == "Transform - Win32 Release"
+
+# Begin Custom Build
+InputPath=.\Scanner.l
+
+"Scanner.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ flex Scanner.l
+ echo #include "IceUtil/Config.h" > Scanner.cpp
+ type lex.yy.c >> Scanner.cpp
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Transform - Win32 Debug"
+
+# Begin Custom Build
+InputPath=.\Scanner.l
+
+"Scanner.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ flex Scanner.l
+ echo #include "IceUtil/Config.h" > Scanner.cpp
+ type lex.yy.c >> Scanner.cpp
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
|