summaryrefslogtreecommitdiff
path: root/cpp/src/FreezeScript/TransformAnalyzer.cpp
diff options
context:
space:
mode:
authorMark Spruiell <mes@zeroc.com>2004-01-16 22:22:44 +0000
committerMark Spruiell <mes@zeroc.com>2004-01-16 22:22:44 +0000
commit00081d77200a08baac2e62cc2797c7530caacea3 (patch)
tree69a638dc86939389e9c810946a7d0fef20a31cd4 /cpp/src/FreezeScript/TransformAnalyzer.cpp
parentadding ClassDef::isA (diff)
downloadice-00081d77200a08baac2e62cc2797c7530caacea3.tar.bz2
ice-00081d77200a08baac2e62cc2797c7530caacea3.tar.xz
ice-00081d77200a08baac2e62cc2797c7530caacea3.zip
initial check-in
Diffstat (limited to 'cpp/src/FreezeScript/TransformAnalyzer.cpp')
-rw-r--r--cpp/src/FreezeScript/TransformAnalyzer.cpp1143
1 files changed, 1143 insertions, 0 deletions
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';
+}