Index: cpp/frams/util/extvalue.cpp
===================================================================
--- cpp/frams/util/extvalue.cpp	(revision 336)
+++ cpp/frams/util/extvalue.cpp	(revision 337)
@@ -24,5 +24,5 @@
 //this lock only protects against ref.counter corruption caused by concurrent reads.
 //read/write conficts and nonatomicity are handled by BarrierObject (at least in theory ;-))
-static pthread_mutex_t extobject_ref_lock=PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t extobject_ref_lock = PTHREAD_MUTEX_INITIALIZER;
 #define REF_LOCK pthread_mutex_lock(&extobject_ref_lock)
 #define REF_UNLOCK pthread_mutex_unlock(&extobject_ref_lock)
@@ -34,9 +34,9 @@
 void ExtObject::incref() const
 {
-if (subtype&1)
-	{
-	REF_LOCK;
-	dbobject->refcount++;
-	REF_UNLOCK;
+	if (subtype & 1)
+	{
+		REF_LOCK;
+		dbobject->refcount++;
+		REF_UNLOCK;
 	}
 }
@@ -44,12 +44,12 @@
 void ExtObject::decref() const
 {
-if (subtype&1)
-	{
-	REF_LOCK;
-	bool destroy=!--dbobject->refcount;
-	REF_UNLOCK;
-	//another thread can now access the object while we are deleting it
-	//but this is not a bug since we only guarantee read/read safety
-	if (destroy) delete dbobject;
+	if (subtype & 1)
+	{
+		REF_LOCK;
+		bool destroy = !--dbobject->refcount;
+		REF_UNLOCK;
+		//another thread can now access the object while we are deleting it
+		//but this is not a bug since we only guarantee read/read safety
+		if (destroy) delete dbobject;
 	}
 }
@@ -57,49 +57,49 @@
 bool ExtObject::operator==(const ExtObject& src) const
 {
-if (object!=src.object) return false;
-const char* n1=interfaceName();
-const char* n2=src.interfaceName();
-return (n1==n2) || (strcmp(n1,n2)==0);
+	if (object != src.object) return false;
+	const char* n1 = interfaceName();
+	const char* n2 = src.interfaceName();
+	return (n1 == n2) || (strcmp(n1, n2) == 0);
 }
 
 bool ExtObject::makeUnique()
 {
-if (!(subtype&1)) return false;
-if (dbobject->refcount==1) return false;
-VectorObject* v=VectorObject::fromObject(*this,false);
-if (v)
-	{
-	VectorObject* n=new VectorObject;
-	n->data.setSize(n->data.size());
-	for(int i=0;i<v->data.size();i++)
-		{
-		ExtValue *x=(ExtValue*)v->data(i);
-		n->data.set(i,x?new ExtValue(*x):NULL);
-		}
-	operator=(n->makeObject());
-	return true;
-	}
-return false;
+	if (!(subtype & 1)) return false;
+	if (dbobject->refcount == 1) return false;
+	VectorObject* v = VectorObject::fromObject(*this, false);
+	if (v)
+	{
+		VectorObject* n = new VectorObject;
+		n->data.setSize(n->data.size());
+		for (int i = 0; i < v->data.size(); i++)
+		{
+			ExtValue *x = (ExtValue*)v->data(i);
+			n->data.set(i, x ? new ExtValue(*x) : NULL);
+		}
+		operator=(n->makeObject());
+		return true;
+	}
+	return false;
 }
 
 void* ExtObject::getTarget(const char* classname, bool through_barrier, bool warn) const
 {
-if (!strcmp(interfaceName(),classname))
-	return getTarget();
+	if (!strcmp(interfaceName(), classname))
+		return getTarget();
 #ifndef NO_BARRIER
-if (through_barrier)
-	{
-	BarrierObject *bo=BarrierObject::fromObject(*this);
-	if (bo)
-		return bo->getSourceObject().getTarget(classname,true,warn);
+	if (through_barrier)
+	{
+		BarrierObject *bo = BarrierObject::fromObject(*this);
+		if (bo)
+			return bo->getSourceObject().getTarget(classname, true, warn);
 	}
 #endif
 
-if (warn)
-	{
-	FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,interfaceName());
-	}
-
-return NULL;
+	if (warn)
+	{
+		FMprintf("ExtValue", "getObjectTarget", FMLV_WARN, "%s object expected, %s found", classname, interfaceName());
+	}
+
+	return NULL;
 }
 
@@ -107,52 +107,52 @@
 SString ExtObject::toString() const
 {
-if (isEmpty()) return SString("null");
-Param tmp_param;
-ParamInterface *p=getParamInterface(tmp_param);
-int tostr=p->findId("toString");
-if (tostr>=0)
-	{
-	return SString(p->getString(tostr));
-	}
-else
-	{
-	SString tmp("<");
-	tmp+=p->getName();
-	tmp+=SString::sprintf(" object at %p>",object?object:paraminterface);
-	return tmp;
-	}
-}
-
-THREAD_LOCAL_DEF(ExtObject::Serialization,ExtObject::serialization);
+	if (isEmpty()) return SString("null");
+	Param tmp_param;
+	ParamInterface *p = getParamInterface(tmp_param);
+	int tostr = p->findId("toString");
+	if (tostr >= 0)
+	{
+		return SString(p->getString(tostr));
+	}
+	else
+	{
+		SString tmp("<");
+		tmp += p->getName();
+		tmp += SString::sprintf(" object at %p>", object ? object : paraminterface);
+		return tmp;
+	}
+}
+
+THREAD_LOCAL_DEF(ExtObject::Serialization, ExtObject::serialization);
 
 void ExtObject::Serialization::begin()
 {
-if (level==0)
-	refs.clear();
-level++;
+	if (level == 0)
+		refs.clear();
+	level++;
 }
 
 int ExtObject::Serialization::add(const ExtObject &o)
 {
-if (o.isEmpty()) return -1;
-for(int i=0;i<(int)refs.size();i++)
-	{
-	ExtObject& r=refs[i];
-	if (r==o) return i;
-	}
-refs.push_back(o);
-return -1;
-}
-
-void ExtObject::Serialization::replace(const ExtObject& o,const ExtObject& other)
-{
-if (o.isEmpty()) return;
-for(int i=0;i<(int)refs.size();i++)
-	{
-	ExtObject& r=refs[i];
-	if (r==o)
-		{
-		r=other;
-		return;
+	if (o.isEmpty()) return -1;
+	for (int i = 0; i < (int)refs.size(); i++)
+	{
+		ExtObject& r = refs[i];
+		if (r == o) return i;
+	}
+	refs.push_back(o);
+	return -1;
+}
+
+void ExtObject::Serialization::replace(const ExtObject& o, const ExtObject& other)
+{
+	if (o.isEmpty()) return;
+	for (int i = 0; i < (int)refs.size(); i++)
+	{
+		ExtObject& r = refs[i];
+		if (r == o)
+		{
+			r = other;
+			return;
 		}
 	}
@@ -161,9 +161,9 @@
 void ExtObject::Serialization::remove(const ExtObject& o)
 {
-if (o.isEmpty()) return;
-for(int i=0;i<(int)refs.size();i++)
-	{
-	ExtObject& r=refs[i];
-	if (o==r) refs.erase(refs.begin()+i);
+	if (o.isEmpty()) return;
+	for (int i = 0; i < (int)refs.size(); i++)
+	{
+		ExtObject& r = refs[i];
+		if (o == r) refs.erase(refs.begin() + i);
 	}
 }
@@ -171,61 +171,61 @@
 const ExtObject* ExtObject::Serialization::get(int ref)
 {
-if (ref<0) return NULL;
-if (ref>=(int)refs.size()) return NULL;
-return &refs[ref];
+	if (ref < 0) return NULL;
+	if (ref >= (int)refs.size()) return NULL;
+	return &refs[ref];
 }
 
 void ExtObject::Serialization::end()
 {
-level--;
-if (level==0)
-	refs.clear();
+	level--;
+	if (level == 0)
+		refs.clear();
 }
 
 SString ExtObject::serialize_inner() const
 {
-int ref=tlsGetRef(serialization).add(*this);
-if (ref>=0)
-	return SString::sprintf("^%d",ref);
-
-if (isEmpty()) return SString("null");
-VectorObject *vec=VectorObject::fromObject(*this,false);
-if (vec)
-	return vec->serialize();
-DictionaryObject *dic=DictionaryObject::fromObject(*this,false);
-if (dic)
-	return dic->serialize();
-Param tmp_param;
-ParamInterface *p=getParamInterface(tmp_param);
-int m=p->findId("toVector");
-if (m<0) 
-	m=p->findId("toDictionary");
-if (m>=0)
-	{
-	ExtObject o(p->getObject(m));
-	SString ret=SString(interfaceName())+o.serialize();
+	int ref = tlsGetRef(serialization).add(*this);
+	if (ref >= 0)
+		return SString::sprintf("^%d", ref);
+
+	if (isEmpty()) return SString("null");
+	VectorObject *vec = VectorObject::fromObject(*this, false);
+	if (vec)
+		return vec->serialize();
+	DictionaryObject *dic = DictionaryObject::fromObject(*this, false);
+	if (dic)
+		return dic->serialize();
+	Param tmp_param;
+	ParamInterface *p = getParamInterface(tmp_param);
+	int m = p->findId("toVector");
+	if (m < 0)
+		m = p->findId("toDictionary");
+	if (m >= 0)
+	{
+		ExtObject o(p->getObject(m));
+		SString ret = SString(interfaceName()) + o.serialize();
+		return ret;
+	}
+	m = p->findId("toString");
+	if (m >= 0)
+	{
+		SString str = p->getString(m);
+		sstringQuote(str);
+		SString ret = SString(interfaceName()) + "\"" + str + "\"";
+		return ret;
+	}
+
+	tlsGetRef(serialization).remove(*this);//undo nonserializable reference
+	SString ret = interfaceName();
+	ret += SString::sprintf("<%p>", object ? object : paraminterface);
 	return ret;
-	}
-m=p->findId("toString");
-if (m>=0)
-	{
-	SString str=p->getString(m);
-	sstringQuote(str);
-	SString ret=SString(interfaceName())+"\""+str+"\"";
+}
+
+SString ExtObject::serialize() const
+{
+	tlsGetRef(serialization).begin();
+	SString ret = serialize_inner();
+	tlsGetRef(serialization).end();
 	return ret;
-	}
-
-tlsGetRef(serialization).remove(*this);//undo nonserializable reference
-SString ret=interfaceName();
-ret+=SString::sprintf("<%p>",object?object:paraminterface);
-return ret;
-}
-
-SString ExtObject::serialize() const
-{
-tlsGetRef(serialization).begin();
-SString ret=serialize_inner();
-tlsGetRef(serialization).end();
-return ret;
 }
 
@@ -234,36 +234,50 @@
 SString ExtValue::typeDescription() const
 {
-switch(type)
-	{
-	case TInt: return SString("integer value");
-	case TDouble: return SString("floating point value");
-	case TString: return SString("text string");
-	case TUnknown: return SString("null value");
-	case TInvalid: return SString("invalid value");
-	case TObj: return getObject().isEmpty()?SString("null"):(SString(getObject().interfaceName())+" object");
-	}
-return SString::empty();
-}
-
-void *ExtValue::getObjectTarget(const char* classname,bool warn) const
-{
-if (type!=TObj)
-	{
-	if (warn)
-		{
-		SString tmp=getString();
-		if (tmp.len()>30) tmp=tmp.substr(0,30)+"...";
-		if (type==TString) tmp=SString("\"")+tmp+SString("\"");
-		FMprintf("ExtValue","getObjectTarget",FMLV_WARN,"%s object expected, %s found",classname,(const char*)tmp);
-		}
-	return NULL;
-	}
-
-return getObject().getTarget(classname,true,warn);
+	switch (type)
+	{
+	case TInt: return SString("int");
+	case TDouble: return SString("float");
+	case TString: return SString("string");
+	case TUnknown: return SString("null");
+	case TInvalid: return SString("invalid");
+	case TObj: return getObject().isEmpty() ? SString("null") : SString(getObject().interfaceName());
+	}
+	return SString::empty();
+}
+
+SString ExtValue::typeAndValue() const
+{
+	SString msg = typeDescription();
+	switch (type)
+	{
+	case TInt: case TDouble: case TString: case TObj:
+		msg += " '";
+		msg += getString();
+		msg += "'";
+	default:;
+	}
+	return msg;
+}
+
+void *ExtValue::getObjectTarget(const char* classname, bool warn) const
+{
+	if (type != TObj)
+	{
+		if (warn)
+		{
+			SString tmp = getString();
+			if (tmp.len() > 30) tmp = tmp.substr(0, 30) + "...";
+			if (type == TString) tmp = SString("\"") + tmp + SString("\"");
+			FMprintf("ExtValue", "getObjectTarget", FMLV_WARN, "%s object expected, %s found", classname, (const char*)tmp);
+		}
+		return NULL;
+	}
+
+	return getObject().getTarget(classname, true, warn);
 }
 
 void ExtValue::set(const ExtValue& src)
 {
-switch(src.type)
+	switch (src.type)
 	{
 	case TString: sets(src.sdata()); break;
@@ -271,5 +285,5 @@
 	case TDouble: setd(src.ddata()); break;
 	case TObj: seto(src.odata()); break;
-	default:type=src.type; break;
+	default:type = src.type; break;
 	}
 }
@@ -277,5 +291,5 @@
 void ExtValue::setEmpty()
 {
-switch(type)
+	switch (type)
 	{
 #ifdef EXTVALUEUNION
@@ -288,57 +302,61 @@
 	default:;
 	}
-type=TUnknown;
+	type = TUnknown;
 }
 
 static ExtValue::CompareResult longsign(paInt x)
 {
-if (x<0) return ExtValue::ResultLower;
-if (x>0) return ExtValue::ResultHigher;
-return ExtValue::ResultEqual;
+	if (x < 0) return ExtValue::ResultLower;
+	if (x > 0) return ExtValue::ResultHigher;
+	return ExtValue::ResultEqual;
 }
 
 static ExtValue::CompareResult compareNull(const ExtValue& v)
 {
-if (v.isNull()) return ExtValue::ResultEqualUnordered;
-if ((v.getType()==TInt)&&(v.getInt()==0)) return ExtValue::ResultUnequal_RelaxedEqual;
-return ExtValue::ResultUnequal_RelaxedUnequal; //comparing anything else with null is valid but null is neither higher nor lower than numbers or strings
-}
-
-static ExtValue::CompareResult compareFloat(double a,double b)
-{
-double t=a-b;
-if (t<0) return ExtValue::ResultLower;
-else if (t>0) return ExtValue::ResultHigher;
-return ExtValue::ResultEqual;
-}
-
-static ExtValue::CompareResult compareString(const SString &a,const SString &b)
-{
-const char* s1=(const char*)a;
-const char* s2=(const char*)b;
-return longsign(strcmp(s1,s2));
+	if (v.isNull()) return ExtValue::ResultEqualUnordered;
+	if ((v.getType() == TInt) && (v.getInt() == 0)) return ExtValue::ResultUnequal_RelaxedEqual;
+	return ExtValue::ResultUnequal_RelaxedUnequal; //comparing anything else with null is valid but null is neither higher nor lower than numbers or strings
+}
+
+static ExtValue::CompareResult compareFloat(double a, double b)
+{
+	double t = a - b;
+	if (t < 0) return ExtValue::ResultLower;
+	else if (t > 0) return ExtValue::ResultHigher;
+	return ExtValue::ResultEqual;
+}
+
+static ExtValue::CompareResult compareString(const SString &a, const SString &b)
+{
+	const char* s1 = (const char*)a;
+	const char* s2 = (const char*)b;
+	return longsign(strcmp(s1, s2));
 }
 
 ExtValue::CompareResult ExtValue::compare(const ExtValue& src) const
 {
-if (isNull())
-	return compareNull(src);
-else if (src.isNull())
-	return compareNull(*this);
-switch(type)
+	if (isNull())
+		return compareNull(src);
+	else if (src.isNull())
+		return compareNull(*this);
+	switch (type)
 	{
 
 	case TInt:
 
-		if (src.getType()==TInt)
-			{
-			paInt t=src.getInt();
-			if (idata()>0)
-				{if (t>0) return longsign(idata()-t); else return ResultHigher;}
+		if (src.getType() == TInt)
+		{
+			paInt t = src.getInt();
+			if (idata() > 0)
+			{
+				if (t > 0) return longsign(idata() - t); else return ResultHigher;
+			}
 			else
-				{if (t<=0) return longsign(idata()-t); else return ResultLower;}
-			}
-		else if (src.getType()==TDouble)
-			return compareFloat((double)idata(),src.getDouble());
+			{
+				if (t <= 0) return longsign(idata() - t); else return ResultLower;
+			}
+		}
+		else if (src.getType() == TDouble)
+			return compareFloat((double)idata(), src.getDouble());
 		else
 			return ResultMismatch;//comparing numbers with other things is invalid
@@ -346,6 +364,6 @@
 
 	case TDouble:
-		if ((src.getType()==TDouble)||(src.getType()==TInt))
-			return compareFloat(getDouble(),src.getDouble());
+		if ((src.getType() == TDouble) || (src.getType() == TInt))
+			return compareFloat(getDouble(), src.getDouble());
 		else
 			return ResultMismatch;
@@ -353,173 +371,225 @@
 
 	case TString:
-		if (src.getType()==TString)
-			return compareString(sdata(),src.getString());
+		if (src.getType() == TString)
+			return compareString(sdata(), src.getString());
 		else
 			return ResultMismatch;
 		break;
 
-	case TObj: 
-	{
-	if (src.type==TObj)
-		return odata()==src.odata() ? ResultEqualUnordered : ResultUnequal_RelaxedUnequal;
-	if ((src.type==TInt)&&(src.getInt()==0))
-		return ResultMismatch_RelaxedUnequal;
+	case TObj:
+	{
+		if (src.type == TObj)
+			return odata() == src.odata() ? ResultEqualUnordered : ResultUnequal_RelaxedUnequal;
+		if ((src.type == TInt) && (src.getInt() == 0))
+			return ResultMismatch_RelaxedUnequal;
+		return ResultMismatch;
+	}
+	default:;
+	}
 	return ResultMismatch;
-	}
+}
+
+const char* ExtValue::cmp_op_names[] = { "==", "!=", ">=", "<=", ">", "<", "~=", "!~", NULL };
+
+int ExtValue::interpretCompare(CmpOperator op, CompareResult result, CmpContext *context)
+{
+	CompareResult error_threshold = ResultUnequal_RelaxedEqual;//error when ResultUnequal_RelaxedEqual or higher (not comparable)
+	int ret = 0;
+	switch (op)
+	{
+	case CmpEQ: ret = (result == ResultEqual) || (result == ResultEqualUnordered); error_threshold = ResultMismatch_RelaxedUnequal; break;
+	case CmpNE: ret = !((result == ResultEqual) || (result == ResultEqualUnordered)); error_threshold = ResultMismatch_RelaxedUnequal; break;
+	case CmpGT: ret = (result == ResultHigher); error_threshold = ResultEqualUnordered; break;
+	case CmpGE: ret = (result == ResultEqual) || (result == ResultHigher); error_threshold = ResultEqualUnordered; break;
+	case CmpLT: ret = (result == ResultLower); error_threshold = ResultEqualUnordered; break;
+	case CmpLE: ret = (result == ResultEqual) || (result == ResultLower); error_threshold = ResultEqualUnordered; break;
+	case CmpREQ: ret = (result == ResultEqual) || (result == ResultEqualUnordered) || (result == ResultUnequal_RelaxedEqual); error_threshold = ResultMismatch; break;
+	case CmpRNE: ret = !((result == ResultEqual) || (result == ResultEqualUnordered) || (result == ResultUnequal_RelaxedEqual)); error_threshold = ResultMismatch; break;
 	default:;
 	}
-return ResultMismatch;
-}
-
-ExtValue::CmpMessageHandler ExtValue::default_cmp_message;
-ExtValue::CmpContext ExtValue::default_cmp_context={NULL,NULL,&default_cmp_message};
-
-const char* ExtValue::cmp_op_names[]={"==","!=",">=","<=",">","<","~=","!~",NULL};
-
-void ExtValue::CmpMessageHandler::cmpMessage(SString& text)
-{
-FMprintf("ExtValue","interpretCompare",FMLV_ERROR,"%s",(const char*)text);
-}
-
-int ExtValue::interpretCompare(CmpOperator op,CompareResult result,CmpContext *context)
-{
-CompareResult error_threshold=ResultUnequal_RelaxedEqual;//error when ResultUnequal_RelaxedEqual or higher (not comparable)
-int ret=0;
-switch (op)
-	{
-	case CmpEQ: ret=(result==ResultEqual)||(result==ResultEqualUnordered); error_threshold=ResultMismatch_RelaxedUnequal; break;
-	case CmpNE: ret=!((result==ResultEqual)||(result==ResultEqualUnordered)); error_threshold=ResultMismatch_RelaxedUnequal; break;
-	case CmpGT: ret=(result==ResultHigher); error_threshold=ResultEqualUnordered; break;
-	case CmpGE: ret=(result==ResultEqual)||(result==ResultHigher); error_threshold=ResultEqualUnordered; break;
-	case CmpLT: ret=(result==ResultLower); error_threshold=ResultEqualUnordered; break;
-	case CmpLE: ret=(result==ResultEqual)||(result==ResultLower); error_threshold=ResultEqualUnordered; break;
-	case CmpREQ: ret=(result==ResultEqual)||(result==ResultEqualUnordered)||(result==ResultUnequal_RelaxedEqual); error_threshold=ResultMismatch; break;
-	case CmpRNE: ret=!((result==ResultEqual)||(result==ResultEqualUnordered)||(result==ResultUnequal_RelaxedEqual)); error_threshold=ResultMismatch; break;
+	if (result >= error_threshold)
+	{
+		SString msg = "Type mismatch while comparing";
+		if (context)
+		{
+			if (context->v1 && context->v2)
+				msg += SString::sprintf(": %s %s %s",
+				(const char*)context->v1->typeAndValue(),
+				cmp_op_names[op - CmpFIRST],
+				(const char*)context->v2->typeAndValue());
+		}
+		FMprintf("ExtValue", "interpretCompare", FMLV_ERROR, "%s", (const char*)msg);
+		ret = -1;
+	}
+	return ret;
+}
+
+int ExtValue::operator==(const ExtValue& src) const
+{
+	if (type != src.type) return 0;
+	switch (type)
+	{
+	case TInt: return idata() == src.idata();
+	case TDouble: return ddata() == src.ddata();
+	case TString: return sdata() == src.sdata();
+	case TObj: return odata() == src.odata();
 	default:;
 	}
-if (result >= error_threshold)
-	{
-	if (context)
-		{
-		SString msg="Type mismatch while comparing";
-		if (context->v1 && context->v2)
-			{
-			const char* opname=cmp_op_names[op-CmpFIRST];
-			msg+=": ";
-			if (context->v1->isNull())
-				msg+="null ";
-			else
-				msg+=SString::sprintf("%s '%s' ",(const char*)context->v1->typeDescription(),(const char*)context->v1->getString());
-			msg+=opname;
-			if (context->v2->isNull())
-				msg+=" null";
-			else
-				msg+=SString::sprintf(" %s '%s'",(const char*)context->v2->typeDescription(),(const char*)context->v2->getString());
-			}
-		context->handler->cmpMessage(msg);
-		}
-	ret=-1;
-	}
-return ret;
-}
-
-int ExtValue::operator==(const ExtValue& src) const
-{
-if (type!=src.type) return 0;
-switch(type)
-	{
-	case TInt: return idata()==src.idata();
-	case TDouble: return ddata()==src.ddata();
-	case TString: return sdata()==src.sdata();
-	case TObj: return odata()==src.odata();
+	return 1;
+}
+
+void ExtValue::operator+=(const ExtValue& src)
+{
+	// return = ok, break = fail
+	switch (type)
+	{
+	case TInt:
+		switch (src.getType())
+		{
+		case TDouble:
+			FMprintf("ExtValue", "add", FMLV_WARN, "Adding %s to %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
+			setDouble(double(getInt()) + src.getDouble());
+			return;
+		case TString:
+			break;
+		default:
+			idata() += src.getInt();
+			return;
+		}
+		break;
+	case TDouble:
+		switch (src.getType())
+		{
+		case TString:
+			break;
+		default:
+			ddata() += src.getDouble();
+			return;
+		}
+		break;
+	case TString: sdata() += src.getString(); return;
+	case TObj:
+	{
+		VectorObject *vec = VectorObject::fromObject(getObject(), false);
+		VectorObject *vec2 = VectorObject::fromObject(src.getObject(), false);
+		if (vec && vec2)
+		{
+			for (int i = 0; i < vec2->data.size(); i++)
+			{
+				ExtValue *s = (ExtValue*)vec2->data(i);
+				ExtValue *d = s ? new ExtValue(*s) : NULL;
+				vec->data += d;
+			}
+			return;
+		}
+	}
+		//NO break;
 	default:;
 	}
-return 1;
-}
-
-void ExtValue::operator+=(const ExtValue& src)
-{
-switch(type)
-	{
-	case TInt: idata()+=src.getInt(); break;
-	case TDouble: ddata()+=src.getDouble(); break;
-	case TString: sdata()+=src.getString(); break;
+	FMprintf("ExtValue", "add", FMLV_ERROR, "Can't add %s to %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
+}
+
+void ExtValue::operator-=(const ExtValue& src)
+{
+	// return = ok, break = fail
+	switch (type)
+	{
+	case TInt:
+		switch (src.getType())
+		{
+		case TInt:
+			idata() -= src.getInt();
+			return;
+		case TDouble:
+			FMprintf("ExtValue", "subtract", FMLV_WARN, "Subtracting %s from %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
+			setDouble(double(getInt()) - src.getDouble());
+			return;
+		default:;
+		}
+		break;
+	case TDouble:
+		switch (src.getType())
+		{
+		case TDouble:
+		case TInt:
+			ddata() -= src.getDouble();
+			return;
+		default:;
+		}
+		break;
+	default:;
+	}
+	FMprintf("ExtValue", "subtract", FMLV_ERROR, "Can't subtract %s from %s", (const char*)src.typeAndValue(), (const char*)typeAndValue());
+}
+
+void ExtValue::operator*=(const ExtValue& src)
+{
+	// return = ok, break = fail
+	switch (type)
+	{
+	case TInt:
+		switch (src.getType())
+		{
+		case TInt:
+			idata() *= src.getInt();
+			return;
+		case TDouble:
+			FMprintf("ExtValue", "multiply", FMLV_WARN, "Multiplying %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
+			setDouble(double(getInt())*src.getDouble());
+			return;
+		default:;
+		}
+		break;
+	case TDouble:
+		switch (src.getType())
+		{
+		case TInt:
+		case TDouble:
+			ddata() *= src.getDouble();
+			return;
+		default:;
+		}
+		break;
+	case TString:
+		switch (src.getType())
+		{
+		case TInt: case TDouble:
+		{
+			SString t;
+			for (int n = src.getInt(); n > 0; n--)
+				t += getString();
+			setString(t);
+			return;
+		}
+		default:;
+		}
+		break;
 	case TObj:
-		{
-		VectorObject *vec=VectorObject::fromObject(getObject(),false);
-		VectorObject *vec2=VectorObject::fromObject(src.getObject(),false);
-		if (vec && vec2)
-			{
-			for(int i=0;i<vec2->data.size();i++)
+	{
+		VectorObject *vec = VectorObject::fromObject(getObject(), false);
+		if (vec)
+		{
+			int n = src.getInt();
+			int orig_size = vec->data.size();
+			if (n <= 0)
+			{
+				vec->clear(); return;
+			}
+			for (; n > 1; n--)
+			{
+				for (int i = 0; i < orig_size; i++)
 				{
-				ExtValue *s=(ExtValue*)vec2->data(i);
-				ExtValue *d=s?new ExtValue(*s):NULL;
-				vec->data+=d;
+					ExtValue *s = (ExtValue*)vec->data(i);
+					ExtValue *d = s ? new ExtValue(*s) : NULL;
+					vec->data += d;
 				}
-			return;
-			}
-		}
+			}
+			return;
+		}
+	}
 		//NO break;
-	case TUnknown:
-	case TInvalid:
-		FMprintf("ExtValue","operator+=",FMLV_WARN,"Can't add %s to %s",(const char*)src.typeDescription(),(const char*)typeDescription());
 	default:;
 	}
-}
-
-void ExtValue::operator-=(const ExtValue& src)
-{
-switch(type)
-	{
-	case TInt: idata()-=src.getInt(); break;
-	case TDouble: ddata()-=src.getDouble(); break;
-	case TString: case TObj: case TUnknown: case TInvalid:
-		FMprintf("ExtValue","operator-=",FMLV_WARN,"Can't subtract %s from %s",(const char*)src.typeDescription(),(const char*)typeDescription());
-		break;
-	default:;
-	}
-}
-
-void ExtValue::operator*=(const ExtValue& src)
-{
-switch(type)
-	{
-	case TInt: idata()*=src.getInt(); break;
-	case TDouble: ddata()*=src.getDouble(); break;
-	case TString:
-	{
-	SString t;
-	for(int n=src.getInt();n>0;n--)
-		t+=getString();
-	setString(t);
-	break;
-	}
-	case TObj:
-		{
-		VectorObject *vec=VectorObject::fromObject(getObject(),false);
-		if (vec)
-			{
-			int n=src.getInt();
-			int orig_size=vec->data.size();
-			if (n<=0)
-				{vec->clear();return;}
-			for(;n>1;n--)
-				{
-				for(int i=0;i<orig_size;i++)
-					{
-					ExtValue *s=(ExtValue*)vec->data(i);
-					ExtValue *d=s?new ExtValue(*s):NULL;
-					vec->data+=d;
-					}
-				}
-			return;
-			}
-		}
-		//NO break;
-	case TUnknown: case TInvalid:
-		FMprintf("ExtValue","operator*=",FMLV_WARN,"Can't multiply %s by %s",(const char*)typeDescription(),(const char*)src.typeDescription());
-		break;
-	default:;
-	}
+	FMprintf("ExtValue", "multiply", FMLV_WARN, "Can't multiply %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
 }
 
@@ -536,147 +606,178 @@
 } */
 
+void ExtValue::divInt(paInt a)
+{
+	if (a)
+		idata() /= a;
+	else
+	{
+		FMprintf("ExtValue", "divide", FMLV_CRITICAL, "Division by zero: %d/0", idata());
+		setInvalid();
+	}
+}
+
+void ExtValue::divDouble(double a)
+{
+	if (a == 0.0)
+	{
+		FMprintf("ExtValue", "divide", FMLV_CRITICAL, "Division by zero: %s/0.0", (const char*)getString());
+		setInvalid();
+	}
+	else
+	{
+		fpExceptDisable();
+		double tmp = getDouble() / a;
+		if (!finite(tmp))
+		{
+			FMprintf("ExtValue", "divide", FMLV_CRITICAL, "Overflow %s/%g", (const char*)getString(), a); setInvalid();
+		}
+		else
+			setDouble(tmp);
+		// niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
+		//if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
+		//	  { FMprintf("ExtValue","divide",FMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
+		fpExceptEnable();
+	}
+}
+
 void ExtValue::operator/=(const ExtValue& src)
 {
-switch(type)
+	switch (type)
 	{
 	case TInt:
-	{ int a=src.getInt();
-//		idata()/=src.getInt();
-	if (a) idata()/=a;
-	else {FMprintf("ExtValue","divide",FMLV_CRITICAL,"%d/0",idata()); setInvalid();}
-	}
+		switch (src.getType())
+		{
+		case TInt:
+			divInt(src.idata());
+			return;
+		case TDouble:
+			FMprintf("ExtValue", "divide", FMLV_WARN, "Dividing %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
+			divDouble(src.ddata());
+			return;
+		default:;
+		}
 		break;
 
 	case TDouble:
-		{
-		double d=src.getDouble();
-		if (d==0.0)
-			{
-			FMprintf("ExtValue","divide",FMLV_CRITICAL,"%s/0.0",(const char*)getString());
-			setInvalid();
-			}
+		switch (src.getType())
+		{
+		case TInt:
+			divDouble(src.getDouble());
+			return;
+		case TDouble:
+			divDouble(src.ddata());
+			return;
+		default:;
+		}
+		break;
+
+	default:;
+	}
+	FMprintf("ExtValue", "divide", FMLV_ERROR, "Can't divide %s by %s", (const char*)typeAndValue(), (const char*)src.typeAndValue());
+}
+
+SString ExtValue::format(SString& fmt, const ExtValue **values, int count)
+{
+	SString ret;
+	// "..........%.........%..........%........"
+	//  ^_cur     ^_next
+	//  ^^^^^^^^^^___sub
+	//
+	// "..........%.........%..........%........"
+	//            ^-cur     ^-next
+	//            ^^^^^^^^^^___sub
+	const char* begin = (const char*)fmt, *end = begin + fmt.len(), *curr = begin;
+	int type = 0;
+
+	class Args
+	{
+		const ExtValue **values;
+		int count;
+		int arg;
+	public:
+		Args(const ExtValue **v, int c) :values(v), count(c), arg(0) {}
+		bool finished() { return arg >= count; }
+		const ExtValue *getNext() { const ExtValue *ret = NULL; if ((arg < count) && values[arg]) ret = values[arg]; arg++; return ret; }
+	};
+	Args args(values, count);
+
+	while (curr < end)
+	{
+		const char* next = strchr(curr, '%');
+		if (!next) next = end; else if ((next == curr) && (curr > begin))
+		{
+			next = strchr(next + 1, '%'); if (!next) next = end;
+		}
+		type = 0;
+		if (curr > begin)
+		{
+			type = 0;
+			for (const char* t = curr; t < next; t++)
+				switch (*t)
+			{
+				case 'd': case 'x': case 'X': case 'u': case 'p': case 'c': type = 'd'; t = next; break;
+				case 'f': case 'g': case 'e': type = 'f'; t = next; break;
+				case 's': type = 's'; t = next; break;
+				case 't': case 'T': type = *t; t = next; break;
+				case '%': if (t > begin) { type = *t; t = next; } break;
+			}
+		}
+		if (curr > begin) curr--;
+		const ExtValue *a;
+		if (args.finished() && (type != 0) && (type != '%'))
+		{
+			ret += fmt.substr((int)(curr - begin));
+			break;
+		}
+		SString sub = fmt.substr((int)(curr - begin), (int)(next - curr));
+		switch (type)
+		{
+		case 'd': a = args.getNext(); ret += SString::sprintf((const char*)sub, a ? a->getInt() : 0); break;
+		case 'f': a = args.getNext(); ret += SString::sprintf((const char*)sub, a ? a->getDouble() : 0); break;
+		case 's': {a = args.getNext(); SString tmp; if (a) tmp = a->getString(); ret += SString::sprintf((const char*)sub, (const char*)tmp); } break;
+		case 't': case 'T':
+		{
+			a = args.getNext();
+			time_t ti = a ? a->getInt() : 0;
+			struct tm tm = Convert::localtime(ti);
+			SString timtxt;
+			if (type == 'T')
+				timtxt = SString::sprintf("%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+			else
+				timtxt = Convert::asctime(tm).c_str();
+			ret += timtxt;
+			ret += sub.substr(2);
+		}
+			break;
+		case '%': ret += '%'; ret += sub.substr(2); break;
+		case 0: ret += sub; break;
+		}
+		curr = next + 1;
+	}
+	return ret;
+}
+
+
+void ExtValue::operator%=(const ExtValue& src)
+{
+	switch (type)
+	{
+	case TInt: idata() = idata() % src.getInt(); break;
+	case TDouble: ddata() = fmod(ddata(), src.getDouble()); break;
+
+	case TString:
+	{
+		VectorObject *vec = VectorObject::fromObject(src.getObject(), false);
+		if (vec)
+			sdata() = format(sdata(), (const ExtValue**)&vec->data.getref(0), vec->data.size());
 		else
-			{
-			fpExceptDisable();
-			double tmp=ddata()/d;
-			if (!finite(tmp))
-				{ FMprintf("ExtValue","divide",FMLV_CRITICAL,"overflow %s/%s",(const char*)getString(),(const char*)src.getString()); setInvalid(); }
-			else
-				ddata()=tmp;
-			// niby dobrze ale lepiej byloby to robic bardziej systematycznie a nie tylko w dzieleniu?
-			//if (isnan(ddata())) //http://www.digitalmars.com/d/archives/c++/Traping_divide_by_zero_5728.html
-			//	  { FMprintf("ExtValue","divide",FMLV_ERROR,"not-a-number",(const char*)getString()); setInvalid(); }
-			fpExceptEnable();
-			}
-		}
-		break;
-
-	case TString: case TObj: case TUnknown: case TInvalid:
-		FMprintf("ExtValue","operator/=",FMLV_WARN,"Can't divide %s by %s",(const char*)typeDescription(),(const char*)src.typeDescription());
-		break;
-
-	default:;
-	}
-}
-
-SString ExtValue::format(SString& fmt,const ExtValue **values,int count)
-{
-SString ret;
-// "..........%.........%..........%........"
-//  ^_cur     ^_next
-//  ^^^^^^^^^^___sub
-//
-// "..........%.........%..........%........"
-//            ^-cur     ^-next
-//            ^^^^^^^^^^___sub
-const char* begin=(const char*)fmt, *end=begin+fmt.len(), *curr=begin;
-int type=0;
-
-class Args
-{
-const ExtValue **values;
-int count;
-int arg;
-public:
-Args(const ExtValue **v,int c):values(v),count(c),arg(0) {}
-bool finished() {return arg>=count;}
-const ExtValue *getNext() {const ExtValue *ret=NULL; if ((arg<count)&&values[arg]) ret=values[arg]; arg++; return ret;}
-};
-Args args(values,count);
-
-while(curr<end)
-	{
-	const char* next=strchr(curr,'%');
-	if (!next) next=end; else if ((next==curr)&&(curr>begin))
-		{next=strchr(next+1,'%'); if (!next) next=end;}
-	type=0;
-	if (curr>begin)
-		{
-		type=0;
-		for(const char* t=curr;t<next;t++)
-			switch(*t)
-				{
-				case 'd': case 'x': case 'X': case 'u': case 'p': case 'c': type='d'; t=next; break;
-				case 'f': case 'g': case 'e': type='f'; t=next; break;
-				case 's': type='s'; t=next; break;
-				case 't': case 'T': type=*t; t=next; break;
-				case '%': if (t>begin) {type=*t; t=next;} break;
-				}
-		}
-	if (curr>begin) curr--;
-	const ExtValue *a;
-	if (args.finished() && (type!=0) && (type!='%'))
-		{
-		ret+=fmt.substr((int)(curr-begin));
-		break;
-		}
-	SString sub=fmt.substr((int)(curr-begin),(int)(next-curr));
-	switch(type)
-		{
-		case 'd': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getInt():0); break;
-		case 'f': a=args.getNext(); ret+=SString::sprintf((const char*)sub,a?a->getDouble():0); break;
-		case 's': {a=args.getNext(); SString tmp; if (a) tmp=a->getString(); ret+=SString::sprintf((const char*)sub,(const char*)tmp);} break;
-		case 't': case 'T':
-			{
-			a=args.getNext();
-			time_t ti=a?a->getInt():0;
-			struct tm tm=Convert::localtime(ti);
-			SString timtxt;
-			if (type=='T')
-				timtxt=SString::sprintf("%04d-%02d-%02d %02d:%02d:%02d",1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
-			else
-				timtxt=Convert::asctime(tm).c_str();
-			ret+=timtxt;
-			ret+=sub.substr(2);
-			}
-			break;
-		case '%': ret+='%'; ret+=sub.substr(2); break;
-		case 0: ret+=sub; break;
-		}
-	curr=next+1;
-	}
-return ret;
-}
-
-
-void ExtValue::operator%=(const ExtValue& src)
-{
-switch(type)
-	{
-	case TInt: idata()=idata()%src.getInt(); break;
-	case TDouble: ddata()=fmod(ddata(),src.getDouble()); break;
-
-	case TString:
-	{
-	VectorObject *vec=VectorObject::fromObject(src.getObject(),false);
-	if (vec)
-		sdata()=format(sdata(),(const ExtValue**)&vec->data.getref(0),vec->data.size());
-	else
-		{const ExtValue *ptr=&src; sdata()=ExtValue::format(sdata(),&ptr,1);}
-	}
-	break;
+		{
+			const ExtValue *ptr = &src; sdata() = ExtValue::format(sdata(), &ptr, 1);
+		}
+	}
+		break;
 
 	case TObj: case TUnknown: case TInvalid:
-		FMprintf("ExtValue","operator%=",FMLV_WARN,"Can't apply modulo to %s",(const char*)typeDescription());
+		FMprintf("ExtValue", "modulo", FMLV_WARN, "Can't apply modulo to %s", (const char*)typeDescription());
 
 	default:;
@@ -689,9 +790,9 @@
 	const char* after = tmp.parseNumber(s, strict ? TInt : TUnknown);
 	if ((after == NULL) || (after[0] != 0))
-		{
-		if (error) 
-			FMprintf("ExtValue", "parseInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict?" (strict)":"");
+	{
+		if (error)
+			FMprintf("ExtValue", "parseInt", FMLV_ERROR, "Could not parse '%s'%s", s, strict ? " (strict)" : "");
 		return false;
-		}
+	}
 	result = tmp.getInt();
 	return true;
@@ -703,14 +804,14 @@
 	const char* after = tmp.parseNumber(s, TDouble);
 	if ((after == NULL) || (after[0] != 0))
-		{
-		if (error) 
+	{
+		if (error)
 			FMprintf("ExtValue", "parseDouble", FMLV_ERROR, "Could not parse '%s'", s);
 		return false;
-		}
+	}
 	result = tmp.getDouble();
 	return true;
 }
 
-paInt ExtValue::getInt(const char* s,bool strict)
+paInt ExtValue::getInt(const char* s, bool strict)
 {
 	paInt result;
@@ -780,12 +881,12 @@
 SString ExtValue::serialize() const
 {
-switch(type)
+	switch (type)
 	{
 	case TString:
-		{
-		SString q=sdata();
+	{
+		SString q = sdata();
 		sstringQuote(q);
-		return SString("\"")+q+SString("\"");
-		}
+		return SString("\"") + q + SString("\"");
+	}
 	case TInt:
 		return SString::valueOf(idata());
@@ -811,6 +912,6 @@
 	bool minus = (in[0] == '-');
 	bool plus = (in[0] == '+');
-	if (((in[0] == '0') && ((in[1] == 'x') || (in[1]=='X')))
-	     || (((minus || plus) && (in[1] == '0') && ((in[2] == 'x') || (in[2] == 'X')))))
+	if (((in[0] == '0') && ((in[1] == 'x') || (in[1] == 'X')))
+		|| (((minus || plus) && (in[1] == '0') && ((in[2] == 'x') || (in[2] == 'X')))))
 	{
 		in += (minus || plus) ? 3 : 2;
@@ -854,21 +955,21 @@
 PtrListTempl<ParamInterface*> &ExtValue::getDeserializableClasses()
 {
-static PtrListTempl<ParamInterface*> classes;
-return classes;
+	static PtrListTempl<ParamInterface*> classes;
+	return classes;
 }
 
 ParamInterface *ExtValue::findDeserializableClass(const char* name)
 {
-FOREACH(ParamInterface*,cls,getDeserializableClasses())
-	if (!strcmp(cls->getName(),name))
-		return cls;
-return NULL;
+	FOREACH(ParamInterface*, cls, getDeserializableClasses())
+		if (!strcmp(cls->getName(), name))
+			return cls;
+	return NULL;
 }
 
 static const char* skipWord(const char* in)
 {
-while(isalpha(*in)||(*in=='_'))
-	in++;
-return in;
+	while (isalpha(*in) || (*in == '_'))
+		in++;
+	return in;
 }
 
@@ -876,198 +977,198 @@
 const char* ExtValue::deserialize_inner(const char* in)
 {
-const char* ret=parseNumber(in);
-if (ret)
+	const char* ret = parseNumber(in);
+	if (ret)
+		return ret;
+	else if (*in == '\"')
+	{
+		ret = skipQuoteString(in + 1, NULL);
+		SString s(in + 1, (int)(ret - (in + 1)));
+		sstringUnquote(s);
+		setString(s);
+		if (*ret == '\"')
+			return ret + 1;
+		else
+		{
+			FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing '\"' in string: '%s'", ret);
+			return NULL;
+		}
+	}
+	else if (*in == '[')
+	{
+		VectorObject *vec = new VectorObject;
+		ExtObject o(&VectorObject::par, vec);
+		tlsGetRef(ExtObject::serialization).add(o);
+		const char* p = in + 1;
+		ExtValue tmp;
+		while (*p)
+		{
+			if (*p == ']') { p++; break; }
+			ret = tmp.deserialize(p);
+			if (ret)
+			{
+				vec->data += new ExtValue(tmp);
+				p = ret;
+				if (*p == ',') p++;
+				else if (*p != ']')
+				{
+					FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing ',' in Vector: '%s'", p);
+					return NULL;
+				}
+			}
+			else
+			{
+				p = NULL;
+				break;
+			}
+		}
+		setObject(o);
+		return p;
+	}
+	else if (*in == '{')
+	{
+		DictionaryObject *dic = new DictionaryObject;
+		ExtObject o(&DictionaryObject::par, dic);
+		tlsGetRef(ExtObject::serialization).add(o);
+		const char* p = in + 1;
+		ExtValue args[2]/*={value,key}*/, dummy_ret;
+		while (*p)
+		{
+			if (*p == '}') { p++; break; }
+			ret = args[1].deserialize(p);
+			if ((!ret) || (args[1].getType() != TString)) { p = NULL; break; }
+			p = ret;
+			if (*p != ':') { FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing ':' in Dictionary: '%s'", p); p = NULL; break; }
+			p++;
+			ret = args[0].deserialize(p);
+			if (!ret) { p = NULL; break; }
+			p = ret;
+			dic->p_set(args, &dummy_ret);
+			if (*p == ',') p++;
+			else if (*p != '}')
+			{
+				FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Missing ',' in Dictionary: '%s'", p);
+				return NULL;
+			}
+		}
+		setObject(o);
+		return p;
+	}
+	else if (!strncmp(in, "null", 4))
+	{
+		setEmpty();
+		return in + 4;
+	}
+	else if (!strncmp(in, "invalid", 9))
+	{
+		setInvalid();
+		return in + 9;
+	}
+	else if (*in == '<')
+	{ //unserializable object
+		setInvalid();
+		while (*in)
+			if (*in == '>')
+				return in + 1;
+			else in++;
+			return in;
+	}
+	else if (*in == '^')
+	{
+		in++;
+		ExtValue ref;
+		ret = ref.parseNumber(in, TInt);
+		if (ret && (ref.getType() == TInt))
+		{
+			const ExtObject* o = tlsGetRef(ExtObject::serialization).get(ref.getInt());
+			if (o)
+			{
+				setObject(*o);
+				return ret;
+			}
+		}
+		FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Invalid reference: '%s'", in - 1);
+		return NULL;
+	}
+	else if ((ret = skipWord(in)) && (ret != in))
+	{
+		SString clsname(in, (int)(ret - in));
+		ExtValue tmp;
+		ret = tmp.deserialize(ret);
+		ParamInterface *cls = findDeserializableClass(clsname);
+		if (cls && (tmp.getType() != TUnknown) && (tmp.getType() != TInvalid))
+		{
+			VectorObject *vec = VectorObject::fromObject(tmp.getObject(), false);
+			if (vec)
+			{
+				int m = cls->findId("newFromVector");
+				if (m >= 0)
+				{
+					cls->call(m, &tmp, this);
+					tlsGetRef(ExtObject::serialization).replace(tmp.getObject(), getObject());
+					return ret;
+				}
+			}
+			DictionaryObject *dic = DictionaryObject::fromObject(tmp.getObject(), false);
+			if (dic)
+			{
+				int m = cls->findId("newFromDictionary");
+				if (m >= 0)
+				{
+					cls->call(m, &tmp, this);
+					tlsGetRef(ExtObject::serialization).replace(tmp.getObject(), getObject());
+					return ret;
+				}
+			}
+			if (tmp.getType() == TString)
+			{
+				int m = cls->findId("newFromString");
+				if (m >= 0)
+				{
+					cls->call(m, &tmp, this);
+					tlsGetRef(ExtObject::serialization).replace(tmp.getObject(), getObject());
+					return ret;
+				}
+			}
+			tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
+			setEmpty();
+		}
+		setEmpty();
+		FMprintf("ExtValue", "deserialize", FMLV_WARN, "object of class \"%s\" could not be deserialized", (const char*)clsname);
+		return ret;
+	}
+	FMprintf("ExtValue", "deserialize", FMLV_ERROR, "Bad syntax: '%s'", in);
+	setEmpty();
+	return NULL;
+}
+
+const char* ExtValue::deserialize(const char* in)
+{
+	tlsGetRef(ExtObject::serialization).begin();
+	const char* ret = deserialize_inner(in);
+	tlsGetRef(ExtObject::serialization).end();
 	return ret;
-else if (*in=='\"')
-	{
-	ret=skipQuoteString(in+1,NULL);
-	SString s(in+1,(int)(ret-(in+1)));
-	sstringUnquote(s);
-	setString(s);
-	if (*ret=='\"')
-		return ret+1;
-	else
-		{
-		FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing '\"' in string: '%s'",ret);
-		return NULL;
-		}
-	}
-else if (*in=='[')
-	{
-	VectorObject *vec=new VectorObject;
-	ExtObject o(&VectorObject::par,vec);
-	tlsGetRef(ExtObject::serialization).add(o);
-	const char* p=in+1;
-	ExtValue tmp;
-	while(*p)
-		{
-		if (*p==']') {p++;break;}
-		ret=tmp.deserialize(p);
-		if (ret)
-			{
-			vec->data+=new ExtValue(tmp);
-			p=ret;
-			if (*p==',') p++;
-			else if (*p!=']')
-				{
-				FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing ',' in Vector: '%s'",p);
-				return NULL;
-				}
-			}
-		else
-			{
-			p=NULL;
-			break;
-			}
-		}
-	setObject(o);
-	return p;
-	}
-else if (*in=='{')
-	{
-	DictionaryObject *dic=new DictionaryObject;
-	ExtObject o(&DictionaryObject::par,dic);
-	tlsGetRef(ExtObject::serialization).add(o);
-	const char* p=in+1;
-	ExtValue args[2]/*={value,key}*/, dummy_ret;
-	while(*p)
-		{
-		if (*p=='}') {p++;break;}
-		ret=args[1].deserialize(p);
-		if ((!ret)||(args[1].getType()!=TString)) {p=NULL;break;}
-		p=ret;
-		if (*p!=':') {FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing ':' in Dictionary: '%s'",p);p=NULL;break;}
-		p++;
-		ret=args[0].deserialize(p);
-		if (!ret) {p=NULL;break;}
-		p=ret;
-		dic->p_set(args,&dummy_ret);
-		if (*p==',') p++;
-		else if (*p!='}')
-			{
-			FMprintf("ExtValue","deserialize",FMLV_ERROR,"Missing ',' in Dictionary: '%s'",p);
-			return NULL;
-			}
-		}
-	setObject(o);
-	return p;
-	}
-else if (!strncmp(in,"null",4))
-	{
-	setEmpty();
-	return in+4;
-	}
-else if (!strncmp(in,"invalid",9))
-	{
-	setInvalid();
-	return in+9;
-	}
-else if (*in=='<')
-	{ //unserializable object
-	setInvalid();
-	while(*in)
-		if (*in=='>')
-			return in+1;
-		else in++;
-	return in;
-	}
-else if (*in=='^')
-	{
-	in++;
-	ExtValue ref;
-	ret=ref.parseNumber(in,TInt);
-	if (ret && (ref.getType()==TInt))
-		{
-		const ExtObject* o=tlsGetRef(ExtObject::serialization).get(ref.getInt());
-		if (o)
-			{
-			setObject(*o);
-			return ret;
-			}
-		}
-	FMprintf("ExtValue","deserialize",FMLV_ERROR,"Invalid reference: '%s'",in-1);
-	return NULL;
-	}
-else if ((ret=skipWord(in))&&(ret!=in))
-	{
-	SString clsname(in,(int)(ret-in));
-	ExtValue tmp;
-	ret=tmp.deserialize(ret);
-	ParamInterface *cls=findDeserializableClass(clsname);
-	if (cls && (tmp.getType()!=TUnknown) && (tmp.getType()!=TInvalid))
-		{
-		VectorObject *vec=VectorObject::fromObject(tmp.getObject(),false);
-		if (vec)
-			{
-			int m=cls->findId("newFromVector");
-			if (m>=0)
-				{
-				cls->call(m,&tmp,this);
-				tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
-				return ret;
-				}
-			}
-		DictionaryObject *dic=DictionaryObject::fromObject(tmp.getObject(),false);
-		if (dic)
-			{
-			int m=cls->findId("newFromDictionary");
-			if (m>=0)
-				{
-				cls->call(m,&tmp,this);
-				tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
-				return ret;
-				}
-			}
-		if (tmp.getType()==TString)
-			{
-			int m=cls->findId("newFromString");
-			if (m>=0)
-				{
-				cls->call(m,&tmp,this);
-				tlsGetRef(ExtObject::serialization).replace(tmp.getObject(),getObject());
-				return ret;
-				}
-			}
-		tlsGetRef(ExtObject::serialization).remove(tmp.getObject());
-		setEmpty();
-		}
-	setEmpty();
-	FMprintf("ExtValue","deserialize",FMLV_WARN,"object of class \"%s\" could not be deserialized",(const char*)clsname);
-	return ret;
-	}
-FMprintf("ExtValue","deserialize",FMLV_ERROR,"Bad syntax: '%s'",in);
-setEmpty();
-return NULL;
-}
-
-const char* ExtValue::deserialize(const char* in)
-{
-tlsGetRef(ExtObject::serialization).begin();
-const char* ret=deserialize_inner(in);
-tlsGetRef(ExtObject::serialization).end();
-return ret;
 }
 
 ExtObject ExtValue::getObject() const
 {
-if (type==TObj) return odata();
-return ExtObject();
+	if (type == TObj) return odata();
+	return ExtObject();
 }
 
 ExtValue ExtValue::getExtType()
 {
-static const char* typenames[]={"null","int","float","string","","invalid"};
-if (getType()!=TObj)
-	return ExtValue(typenames[(int)getType()]);
-ExtObject& o=odata();
-return ExtValue(SString(o.isEmpty()?"":o.interfaceName()));
+	static const char* typenames[] = { "null", "int", "float", "string", "", "invalid" };
+	if (getType() != TObj)
+		return ExtValue(typenames[(int)getType()]);
+	ExtObject& o = odata();
+	return ExtValue(SString(o.isEmpty() ? "" : o.interfaceName()));
 }
 
 SString SString::valueOf(const ExtValue& v)
 {
-return v.getString();
+	return v.getString();
 }
 SString SString::valueOf(const ExtObject& v)
 {
-return v.toString();
-}
+	return v.toString();
+}
Index: cpp/frams/util/extvalue.h
===================================================================
--- cpp/frams/util/extvalue.h	(revision 336)
+++ cpp/frams/util/extvalue.h	(revision 337)
@@ -140,10 +140,10 @@
 	enum CompareResult
 	{
-	 ResultLower=-1, ResultEqual=0, ResultHigher=1,
-	 ResultEqualUnordered,
-	 ResultUnequal_RelaxedEqual,
-	 ResultUnequal_RelaxedUnequal,
-	 ResultMismatch_RelaxedUnequal,
-	 ResultMismatch
+		ResultLower = -1, ResultEqual = 0, ResultHigher = 1,
+		ResultEqualUnordered,
+		ResultUnequal_RelaxedEqual,
+		ResultUnequal_RelaxedUnequal,
+		ResultMismatch_RelaxedUnequal,
+		ResultMismatch
 	};
 	// performs all script value comparisons.
@@ -152,13 +152,13 @@
 	CompareResult compare(const ExtValue& src) const;
 
-	enum CmpOperator { CmpFIRST,CmpEQ=CmpFIRST,CmpNE,CmpGE,CmpLE,CmpGT,CmpLT,/*relaxed (not)equal*/CmpREQ,CmpRNE };
+	enum CmpOperator { CmpFIRST, CmpEQ = CmpFIRST, CmpNE, CmpGE, CmpLE, CmpGT, CmpLT,/*relaxed (not)equal*/CmpREQ, CmpRNE };
 	static const char* cmp_op_names[];
-	class CmpMessageHandler { public: virtual void cmpMessage(SString& text); };
-	struct CmpContext { const ExtValue *v1,*v2; CmpMessageHandler *handler; };
-	static CmpMessageHandler default_cmp_message;
-	static CmpContext default_cmp_context;
+	struct CmpContext { const ExtValue *v1, *v2; };
 	// interpret compare() result, optional context controls error messages
 	// @return 0=false, 1=true, -1=undefined (null in script)
-	static int interpretCompare(CmpOperator op,CompareResult result,CmpContext *context=&default_cmp_context);
+	static int interpretCompare(CmpOperator op, CompareResult result, CmpContext *context = NULL);
+
+	void divInt(paInt a);
+	void divDouble(double a);
 
 	int operator==(const ExtValue& src) const;
@@ -197,4 +197,5 @@
 	bool isNull() const { return (type == TUnknown) || ((type == TObj) && odata().isEmpty()); }
 	SString typeDescription() const;//< @return human readable type name (used in error messages)
+	SString typeAndValue() const;//< @return type and value (used in error messages)
 	const char* parseNumber(const char* in, ExtPType strict_type = TUnknown);
 	const char* deserialize(const char* in);//< @return first character after the succesfully parsed string or NULL if failed
Index: cpp/frams/vm/framscript.y
===================================================================
--- cpp/frams/vm/framscript.y	(revision 336)
+++ cpp/frams/vm/framscript.y	(revision 337)
@@ -145,5 +145,5 @@
  {
 #ifdef FRAMSCRIPT_GOTO
-trctx.out->printf("jump :%s\n",str($2)); FMprintf("FramScriptCompiler","translate",FMLV_WARN,"goto is not recommended (%s line %d)",(const char*)trctx.srcname,trctx.line); trctx.emitLine();
+trctx.out->printf("jump :%s\n",str($2)); FMprintf("FramScriptCompiler","translate",FMLV_WARN,"goto is not recommended"); trctx.emitLine();
 #else
 trctx.err->printf("goto is not supported\n");return 1;
@@ -1409,16 +1409,4 @@
 }
 
-class FramscriptCmpMessageHandler: public ExtValue::CmpMessageHandler
-{
-  public:
-void cmpMessage(SString& msg)
-  {
-  FMprintf("FramScriptCompiler","translate",FMLV_WARN,"%s (%s line %d)",(const char*)msg,(const char*)trctx.srcname,trctx.line);
-  //trctx.err->printf("%s",(const char*)msg);
-  }
-};
-
-static FramscriptCmpMessageHandler framscript_cmp_messages;
-
 bool handleCompare(YYSTYPE& result,const YYSTYPE& arg1,const YYSTYPE& arg2,ExtValue::CmpOperator op,const char* opname)
 {
@@ -1432,5 +1420,4 @@
 	context.v1=&arg1;
 	context.v2=&arg2;
-	context.handler=&framscript_cmp_messages;
 	int ret=ExtValue::interpretCompare(op,cmp,&context);
 	if (ret<0)
@@ -1528,5 +1515,5 @@
 {
 if (t.assign && (!t.parens))
-	FMprintf("FramScriptCompiler","translate",FMLV_WARN,"Assignment used as truth value, use double parens if you really mean it (%s line %d)",(const char*)trctx.srcname,trctx.line);
+	FMprintf("FramScriptCompiler","translate",FMLV_WARN,"Assignment used as truth value, use ((double parens)) if you really mean it");
 }
 
