diff options
author | Mark Spruiell <mes@zeroc.com> | 2004-01-16 22:22:44 +0000 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2004-01-16 22:22:44 +0000 |
commit | 00081d77200a08baac2e62cc2797c7530caacea3 (patch) | |
tree | 69a638dc86939389e9c810946a7d0fef20a31cd4 /cpp/src/FreezeScript/AssignVisitor.cpp | |
parent | adding ClassDef::isA (diff) | |
download | ice-00081d77200a08baac2e62cc2797c7530caacea3.tar.bz2 ice-00081d77200a08baac2e62cc2797c7530caacea3.tar.xz ice-00081d77200a08baac2e62cc2797c7530caacea3.zip |
initial check-in
Diffstat (limited to 'cpp/src/FreezeScript/AssignVisitor.cpp')
-rw-r--r-- | cpp/src/FreezeScript/AssignVisitor.cpp | 598 |
1 files changed, 598 insertions, 0 deletions
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); +} |