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:
parent
fb41a4ff70
commit
24670814da
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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")))
|
||||
|
|
Loading…
Reference in New Issue