Implemented identity checking, proper null and undefined values.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5080 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-05-30 13:18:34 +00:00
parent fb41a4ff70
commit 24670814da
3 changed files with 80 additions and 27 deletions

View File

@ -1406,8 +1406,9 @@ ExpOperation* ExpFunction::clone(const char* name) const
ExpOperation* ExpWrapper::clone(const char* name) const
{
XDebug(DebugInfo,"ExpWrapper::clone('%s') [%p]",name,this);
RefObject* r = YOBJECT(RefObject,object());
XDebug(DebugInfo,"ExpWrapper::clone('%s') %s=%p [%p]",
name,(r ? "ref" : "obj"),object(),this);
if (r)
r->ref();
ExpWrapper* op = new ExpWrapper(object(),name);

View File

@ -47,6 +47,22 @@ private:
GenObject* resolve(ObjList& stack, String& name, GenObject* context);
};
class JsNull : public JsObject
{
public:
inline JsNull()
: JsObject(0,"null",true)
{ }
};
class ExpNull : public ExpWrapper
{
public:
inline ExpNull()
: ExpWrapper(new JsNull,"null")
{ }
};
class JsCode : public ScriptCode, public ExpEvaluator
{
public:
@ -54,6 +70,8 @@ public:
OpcBegin = OpcPrivate + 1,
OpcEnd,
OpcIndex,
OpcEqIdentity,
OpcNeIdentity,
OpcFieldOf,
OpcTypeof,
OpcNew,
@ -83,6 +101,8 @@ public:
OpcJRelFalse,
OpcTrue,
OpcFalse,
OpcNull,
OpcUndefined,
OpcInclude,
OpcRequire,
};
@ -113,7 +133,6 @@ protected:
virtual int preProcess(const char*& expr, GenObject* context = 0);
virtual bool getInstruction(const char*& expr, Opcode nested);
virtual bool getSimple(const char*& expr, bool constOnly = false);
virtual bool getNumber(const char*& expr);
virtual Opcode getOperator(const char*& expr);
virtual Opcode getUnaryOperator(const char*& expr);
virtual Opcode getPostfixOperator(const char*& expr);
@ -155,7 +174,9 @@ private:
#define MAKEOP(s,o) { s, JsCode::Opc ## o }
static const TokenDict s_operators[] =
{
MAKEOP(".",FieldOf),
MAKEOP("===", EqIdentity),
MAKEOP("!==", NeIdentity),
MAKEOP(".", FieldOf),
{ 0, 0 }
};
@ -196,10 +217,12 @@ static const TokenDict s_instr[] =
{ 0, 0 }
};
static const TokenDict s_bools[] =
static const TokenDict s_constants[] =
{
MAKEOP("false", False),
MAKEOP("true", True),
MAKEOP("null", Null),
MAKEOP("undefined", Undefined),
{ 0, 0 }
};
@ -211,6 +234,9 @@ static const TokenDict s_preProc[] =
};
#undef MAKEOP
static const ExpNull s_null;
GenObject* JsContext::resolveTop(ObjList& stack, const String& name, GenObject* context)
{
XDebug(DebugAll,"JsContext::resolveTop '%s'",name.c_str());
@ -796,24 +822,6 @@ bool JsCode::getInstruction(const char*& expr, Opcode nested)
return true;
}
bool JsCode::getNumber(const char*& expr)
{
if (inError())
return false;
skipComments(expr);
switch ((JsOpcode)ExpEvaluator::getOperator(expr,s_bools)) {
case OpcFalse:
addOpcode(false);
return true;
case OpcTrue:
addOpcode(true);
return true;
default:
break;
}
return ExpEvaluator::getNumber(expr);
}
ExpEvaluator::Opcode JsCode::getOperator(const char*& expr)
{
if (inError())
@ -881,6 +889,9 @@ const char* JsCode::getOperator(Opcode oper) const
int JsCode::getPrecedence(ExpEvaluator::Opcode oper) const
{
switch (oper) {
case OpcEqIdentity:
case OpcNeIdentity:
return 4;
case OpcNew:
case OpcIndex:
return 12;
@ -907,13 +918,30 @@ bool JsCode::getSeparator(const char*& expr, bool remove)
bool JsCode::getSimple(const char*& expr, bool constOnly)
{
if (ExpEvaluator::getSimple(expr,constOnly))
return true;
if (inError())
return false;
skipComments(expr);
switch ((JsOpcode)ExpEvaluator::getOperator(expr,s_constants)) {
case OpcFalse:
addOpcode(false);
return true;
case OpcTrue:
addOpcode(true);
return true;
case OpcNull:
addOpcode(s_null.ExpOperation::clone());
return true;
case OpcUndefined:
addOpcode(new ExpWrapper(0,"undefined"));
return true;
default:
break;
}
JsObject* jso = parseArray(expr,constOnly);
if (!jso)
jso = parseObject(expr,constOnly);
if (!jso)
return false;
return ExpEvaluator::getSimple(expr,constOnly);
addOpcode(new ExpWrapper(jso));
return true;
}
@ -1002,6 +1030,30 @@ JsObject* JsCode::parseObject(const char*& expr, bool constOnly)
bool JsCode::runOperation(ObjList& stack, const ExpOperation& oper, GenObject* context) const
{
switch ((JsOpcode)oper.opcode()) {
case OpcEqIdentity:
case OpcNeIdentity:
{
ExpOperation* op2 = popValue(stack,context);
ExpOperation* op1 = popValue(stack,context);
if (!op1 || !op2) {
TelEngine::destruct(op1);
TelEngine::destruct(op2);
return gotError("ExpEvaluator stack underflow",oper.lineNumber());
}
ExpWrapper* w1 = YOBJECT(ExpWrapper,op1);
ExpWrapper* w2 = YOBJECT(ExpWrapper,op2);
bool eq = (op1->opcode() == op2->opcode());
if (eq) {
if (w1 || w2)
eq = w1 && w2 && w1->object() == w2->object();
else
eq = (op1->number() == op2->number()) && (*op1 == *op2);
}
if ((JsOpcode)oper.opcode() == OpcNeIdentity)
eq = !eq;
pushOne(stack,new ExpOperation(eq));
}
break;
case OpcBegin:
pushOne(stack,new ExpOperation((Opcode)OpcBegin));
break;

View File

@ -170,7 +170,7 @@ static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int dep
JsObject::JsObject(const char* name, Mutex* mtx, bool frozen)
: ScriptContext(String("[Object ") + name + "]"),
: ScriptContext(String("[object ") + name + "]"),
m_frozen(frozen), m_mutex(mtx)
{
XDebug(DebugAll,"JsObject::JsObject('%s',%p,%s) [%p]",
@ -348,7 +348,7 @@ void JsObject::initialize(ScriptContext* context)
Mutex* mtx = context->mutex();
Lock mylock(mtx);
NamedList& p = context->params();
static_cast<String&>(p) = "[Object Global]";
static_cast<String&>(p) = "[object Global]";
if (!p.getParam(YSTRING("Object")))
addConstructor(p,"Object",new JsObjectObj(mtx));
if (!p.getParam(YSTRING("Function")))