Do proper number conversion for arithmetic operations.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5854 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
oana 2014-06-24 13:36:53 +00:00
parent f73f353c26
commit 7a41ecce69
3 changed files with 68 additions and 29 deletions

View File

@ -1019,10 +1019,11 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
switch (oper.opcode()) {
case OpcDiv:
case OpcMod:
if (!op2->valInteger())
if (!op2->toNumber())
return gotError("Division by zero",oper.lineNumber());
break;
case OpcAdd:
if (op1->isInteger() && op2->isInteger())
if (op1->isNumber() && op2->isNumber())
break;
// turn addition into concatenation
{
@ -1037,6 +1038,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
break;
}
int64_t val = 0;
bool handled = true;
switch (oper.opcode()) {
case OpcAnd:
val = op1->valInteger() & op2->valInteger();
@ -1053,21 +1055,6 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
case OpcShr:
val = op1->valInteger() >> op2->valInteger();
break;
case OpcAdd:
val = op1->valInteger() + op2->valInteger();
break;
case OpcSub:
val = op1->valInteger() - op2->valInteger();
break;
case OpcMul:
val = op1->valInteger() * op2->valInteger();
break;
case OpcDiv:
val = op1->valInteger() / op2->valInteger();
break;
case OpcMod:
val = op1->valInteger() % op2->valInteger();
break;
case OpcLt:
val = (op1->valInteger() < op2->valInteger()) ? 1 : 0;
break;
@ -1087,8 +1074,35 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
val = (*op1 != *op2) ? 1 : 0;
break;
default:
handled = false;
break;
}
if (!handled) {
val = ExpOperation::nonInteger();
int64_t op1Val = op1->toNumber();
int64_t op2Val = op2->toNumber();
if (op1Val != ExpOperation::nonInteger() && op2Val != ExpOperation::nonInteger()) {
switch(oper.opcode()) {
case OpcAdd:
val = op1Val + op2Val;
break;
case OpcSub:
val = op1Val - op2Val;
break;
case OpcMul:
val = op1Val * op2Val;
break;
case OpcDiv:
val = op1Val / op2Val;
break;
case OpcMod:
val = op1Val % op2Val;
break;
default:
break;
}
}
}
TelEngine::destruct(op1);
TelEngine::destruct(op2);
if (boolRes) {
@ -1167,7 +1181,7 @@ bool ExpEvaluator::runOperation(ObjList& stack, const ExpOperation& oper, GenObj
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
switch (oper.opcode()) {
case OpcNeg:
pushOne(stack,new ExpOperation(-op->valInteger()));
pushOne(stack,new ExpOperation(-op->toNumber()));
break;
case OpcNot:
pushOne(stack,new ExpOperation(~op->valInteger()));
@ -1494,6 +1508,13 @@ int64_t ExpOperation::valInteger() const
return isInteger() ? number() : 0;
}
int64_t ExpOperation::toNumber() const
{
if (isInteger())
return number();
return toInt64(nonInteger());
}
bool ExpOperation::valBoolean() const
{
return isInteger() ? (number() != 0) : !null();
@ -1504,7 +1525,7 @@ const char* ExpOperation::typeOf() const
switch (opcode()) {
case ExpEvaluator::OpcPush:
case ExpEvaluator::OpcCopy:
return isInteger() ? ( isBoolean() ? "boolean" : "number" ) : "string";
return isInteger() ? ( isBoolean() ? "boolean" : "number" ) : (isNumber() ? "number" : "string");
case ExpEvaluator::OpcFunc:
return "function";
default:

View File

@ -340,7 +340,7 @@ bool JsObject::runField(ObjList& stack, const ExpOperation& oper, GenObject* con
else {
bool num = true;
ExpOperation* o = YOBJECT(ExpOperation,param);
if (o && !o->isInteger())
if (o && !o->isNumber())
num = false;
ExpEvaluator::pushOne(stack,new ExpOperation(*param,oper.name(),num));
}

View File

@ -949,7 +949,7 @@ public:
inline ExpOperation(const ExpOperation& original)
: NamedString(original.name(),original),
m_opcode(original.opcode()), m_number(original.number()), m_bool(original.isBoolean()),
m_lineNo(0), m_barrier(original.barrier())
m_isNumber(original.isNumber()), m_lineNo(0), m_barrier(original.barrier())
{ }
/**
@ -960,7 +960,7 @@ public:
inline ExpOperation(const ExpOperation& original, const char* name)
: NamedString(name,original),
m_opcode(original.opcode()), m_number(original.number()), m_bool(original.isBoolean()),
m_lineNo(0), m_barrier(original.barrier())
m_isNumber(original.isNumber()), m_lineNo(0), m_barrier(original.barrier())
{ }
/**
@ -974,6 +974,7 @@ public:
m_opcode(ExpEvaluator::OpcPush),
m_number(autoNum ? value.toInt64(nonInteger()) : nonInteger()),
m_bool(autoNum && value.isBoolean()),
m_isNumber(autoNum && (value == YSTRING("NaN") || m_number != nonInteger())),
m_lineNo(0), m_barrier(false)
{ if (m_bool) m_number = value.toBoolean() ? 1 : 0; }
@ -985,7 +986,7 @@ public:
inline explicit ExpOperation(const char* value, const char* name = 0)
: NamedString(name,value),
m_opcode(ExpEvaluator::OpcPush), m_number(nonInteger()), m_bool(false),
m_lineNo(0), m_barrier(false)
m_isNumber(false), m_lineNo(0), m_barrier(false)
{ }
/**
@ -996,7 +997,7 @@ public:
inline explicit ExpOperation(int64_t value, const char* name = 0)
: NamedString(name,"NaN"),
m_opcode(ExpEvaluator::OpcPush),
m_number(value), m_bool(false), m_lineNo(0), m_barrier(false)
m_number(value), m_bool(false), m_isNumber(true), m_lineNo(0), m_barrier(false)
{ if (value != nonInteger()) String::operator=(value); }
/**
@ -1007,7 +1008,7 @@ public:
inline explicit ExpOperation(bool value, const char* name = 0)
: NamedString(name,String::boolText(value)),
m_opcode(ExpEvaluator::OpcPush),
m_number(value ? 1 : 0), m_bool(true),
m_number(value ? 1 : 0), m_bool(true), m_isNumber(true),
m_lineNo(0), m_barrier(false)
{ }
@ -1020,7 +1021,8 @@ public:
*/
inline ExpOperation(ExpEvaluator::Opcode oper, const char* name = 0, int64_t value = nonInteger(), bool barrier = false)
: NamedString(name,""),
m_opcode(oper), m_number(value), m_bool(false), m_lineNo(0), m_barrier(barrier)
m_opcode(oper), m_number(value), m_bool(false), m_isNumber(false),
m_lineNo(0), m_barrier(barrier)
{ }
/**
@ -1032,7 +1034,8 @@ public:
*/
inline ExpOperation(ExpEvaluator::Opcode oper, const char* name, const char* value, bool barrier = false)
: NamedString(name,value),
m_opcode(oper), m_number(nonInteger()), m_bool(false), m_lineNo(0), m_barrier(barrier)
m_opcode(oper), m_number(nonInteger()), m_bool(false), m_isNumber(false),
m_lineNo(0), m_barrier(barrier)
{ }
/**
@ -1045,7 +1048,8 @@ public:
*/
inline ExpOperation(ExpEvaluator::Opcode oper, const char* name, const char* value, int64_t number, bool barrier)
: NamedString(name,value),
m_opcode(oper), m_number(number), m_bool(false), m_lineNo(0), m_barrier(barrier)
m_opcode(oper), m_number(number), m_bool(false), m_isNumber(true),
m_lineNo(0), m_barrier(barrier)
{ }
/**
@ -1076,6 +1080,13 @@ public:
inline bool isBoolean() const
{ return m_bool; }
/**
* Check if a number type value is stored
* @return True if a number type value is stored
*/
inline bool isNumber() const
{ return m_isNumber; }
/**
* Check if this operation acts as an evaluator barrier on the stack
* @return True if an expression should not pop this operation off the stack
@ -1103,7 +1114,7 @@ public:
* @return Assigned number
*/
inline int64_t operator=(int64_t num)
{ m_number = num; String::operator=(num); return num; }
{ m_number = num; String::operator=(num); m_isNumber = true; return num; }
/**
* Retrieve the numeric value of the operation
@ -1111,6 +1122,12 @@ public:
*/
virtual int64_t valInteger() const;
/**
* Convert to number
* @return Value converted to number, NaN if not possible of if stored value is NaN
*/
virtual int64_t toNumber() const;
/**
* Retrieve the boolean value of the operation
* @return True if the operation is to be interpreted as true value
@ -1149,6 +1166,7 @@ private:
ExpEvaluator::Opcode m_opcode;
int64_t m_number;
bool m_bool;
bool m_isNumber;
unsigned int m_lineNo;
bool m_barrier;
};