Fixed prototypal inheritance and constructors.

Fixed Array length - it's a property not a method.


git-svn-id: http://voip.null.ro/svn/yate@5059 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-05-14 19:51:36 +00:00
parent 57577ceb53
commit 9a805ea5a3
3 changed files with 137 additions and 12 deletions

View File

@ -53,7 +53,6 @@ public:
{
params().addParam(new ExpFunction("push"));
params().addParam(new ExpFunction("pop"));
params().addParam(new ExpFunction("length"));
params().addParam(new ExpFunction("concat"));
params().addParam(new ExpFunction("join"));
params().addParam(new ExpFunction("reverse"));
@ -62,13 +61,21 @@ public:
params().addParam(new ExpFunction("slice"));
params().addParam(new ExpFunction("splice"));
params().addParam(new ExpFunction("sort"));
params().addParam("length","0");
}
inline long length()
{ return m_length; }
inline void setLength()
{ params().setParam("length",String((int)m_length)); }
inline void setLength(long len)
{ m_length = len; params().setParam("length",String((int)len)); }
protected:
inline JsArray(Mutex* mtx, const char* name)
: JsObject(mtx,name), m_length(0)
{ }
virtual JsObject* clone(const char* name) const
{ return new JsArray(mutex(),name); }
bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context);
private:
bool runNativeSlice(ObjList& stack, const ExpOperation& oper, GenObject* context);
@ -85,7 +92,6 @@ public:
inline JsObjectObj(Mutex* mtx)
: JsObject("Object",mtx,true)
{
params().addParam(new ExpFunction("constructor"));
}
protected:
bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context);
@ -120,6 +126,11 @@ public:
params().addParam(new ExpFunction("getUTCSeconds"));
}
protected:
inline JsDate(Mutex* mtx, const char* name)
: JsObject(mtx,name)
{ }
virtual JsObject* clone(const char* name) const
{ return new JsDate(mutex(),name); }
bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context);
};
@ -148,6 +159,14 @@ static inline void addObject(NamedList& params, const char* name, JsObject* obj)
params.addParam(new NamedPointer(name,obj,obj->toString()));
}
// Helper function that adds a constructor to a parent
static inline void addConstructor(NamedList& params, const char* name, JsObject* obj)
{
JsFunction* ctr = new JsFunction(obj->mutex(),name);
ctr->params().addParam(new NamedPointer("prototype",obj,obj->toString()));
params.addParam(new NamedPointer(name,ctr,ctr->toString()));
}
// Helper function that pops arguments off a stack to a list in proper order
static int extractArgs(JsObject* obj, ObjList& stack, const ExpOperation& oper, GenObject* context, ObjList& arguments)
{
@ -173,6 +192,14 @@ JsObject::JsObject(const char* name, Mutex* mtx, bool frozen)
params().addParam(new ExpFunction("hasOwnProperty"));
}
JsObject::JsObject(Mutex* mtx, const char* name, bool frozen)
: ScriptContext(name),
m_frozen(frozen), m_mutex(mtx)
{
XDebug(DebugAll,"JsObject::JsObject(%p,'%s',%s) [%p]",
mtx,name,String::boolText(frozen),this);
}
JsObject::~JsObject()
{
XDebug(DebugAll,"JsObject::~JsObject '%s' [%p]",toString().c_str(),this);
@ -191,11 +218,6 @@ bool JsObject::runFunction(ObjList& stack, const ExpOperation& oper, GenObject*
JsFunction* jf = YOBJECT(JsFunction,param);
if (jf)
return jf->runDefined(stack,oper,context);
JsObject* jso = YOBJECT(JsObject,param);
if (jso) {
ExpFunction op("constructor",oper.number());
return jso->runFunction(stack,op,context);
}
return false;
}
@ -303,13 +325,13 @@ void JsObject::initialize(ScriptContext* context)
NamedList& p = context->params();
static_cast<String&>(p) = "[Object Global]";
if (!p.getParam(YSTRING("Object")))
addObject(p,"Object",new JsObjectObj(mtx));
addConstructor(p,"Object",new JsObjectObj(mtx));
if (!p.getParam(YSTRING("Function")))
addObject(p,"Function",new JsFunction(mtx));
addConstructor(p,"Function",new JsFunction(mtx));
if (!p.getParam(YSTRING("Array")))
addObject(p,"Array",new JsArray(mtx));
addConstructor(p,"Array",new JsArray(mtx));
if (!p.getParam(YSTRING("Date")))
addObject(p,"Date",new JsDate(mtx));
addConstructor(p,"Date",new JsDate(mtx));
if (!p.getParam(YSTRING("Math")))
addObject(p,"Math",new JsMath(mtx));
}
@ -327,6 +349,8 @@ bool JsObjectObj::runNative(ObjList& stack, const ExpOperation& oper, GenObject*
bool JsArray::runNative(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsArray::runNative() '%s' in '%s' [%p]",
oper.name().c_str(),toString().c_str(),this);
if (oper.name() == YSTRING("push")) {
// Adds one or more elements to the end of an array and returns the new length of the array.
if (!oper.number())
@ -344,6 +368,7 @@ bool JsArray::runNative(ObjList& stack, const ExpOperation& oper, GenObject* con
TelEngine::destruct(op);
}
m_length += oper.number();
setLength();
ExpEvaluator::pushOne(stack,new ExpOperation(length()));
}
else if (oper.name() == YSTRING("pop")) {
@ -368,6 +393,7 @@ bool JsArray::runNative(ObjList& stack, const ExpOperation& oper, GenObject* con
}
// clear last
params().clearParam(last);
setLength();
}
else if (oper.name() == YSTRING("length")) {
// Reflects the number of elements in an array.
@ -624,6 +650,8 @@ bool JsArray::runNativeSort(ObjList& stack, const ExpOperation& oper, GenObject*
bool JsMath::runNative(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsMath::runNative() '%s' in '%s' [%p]",
oper.name().c_str(),toString().c_str(),this);
if (oper.name() == YSTRING("abs")) {
if (!oper.number())
return false;
@ -670,6 +698,8 @@ bool JsMath::runNative(ObjList& stack, const ExpOperation& oper, GenObject* cont
bool JsDate::runNative(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsDate::runNative() '%s' in '%s' [%p]",
oper.name().c_str(),toString().c_str(),this);
if (oper.name() == YSTRING("now")) {
// Returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC.
ExpEvaluator::pushOne(stack,new ExpOperation((long int)Time::msecNow())); // should check conversion from u_int64_t
@ -783,6 +813,17 @@ bool JsDate::runNative(ObjList& stack, const ExpOperation& oper, GenObject* cont
JsFunction::JsFunction(Mutex* mtx)
: JsObject("Function",mtx,true)
{
init();
}
JsFunction::JsFunction(Mutex* mtx, const char* name)
: JsObject(mtx,String("[function ") + name + "()]",true)
{
init();
}
void JsFunction::init()
{
params().addParam(new ExpFunction("apply"));
params().addParam(new ExpFunction("call"));
@ -790,6 +831,8 @@ JsFunction::JsFunction(Mutex* mtx)
bool JsFunction::runNative(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsFunction::runNative() '%s' in '%s' [%p]",
oper.name().c_str(),toString().c_str(),this);
if (oper.name() == YSTRING("apply")) {
// func.apply(new_this,["array","of","params",...])
if (oper.number() != 2)
@ -807,7 +850,15 @@ bool JsFunction::runNative(ObjList& stack, const ExpOperation& oper, GenObject*
bool JsFunction::runDefined(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
return false;
XDebug(DebugAll,"JsObject::runDefined() in '%s' [%p]",toString().c_str(),this);
JsObject* proto = YOBJECT(JsObject,getField(stack,"prototype",context));
if (proto) {
// found prototype, build object
JsObject* obj = proto->clone();
obj->copyFields(stack,*proto,context);
ExpEvaluator::pushOne(stack,new ExpWrapper(obj,oper.name()));
}
return true;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -131,6 +131,32 @@ bool ScriptContext::runAssign(ObjList& stack, const ExpOperation& oper, GenObjec
return true;
}
bool ScriptContext::copyFields(ObjList& stack, const ScriptContext& original, GenObject* context)
{
bool ok = true;
unsigned int n = original.params().length();
for (unsigned int i = 0; i < n; i++) {
const NamedString* p = original.params().getParam(i);
if (!p)
continue;
NamedString* fld = original.getField(stack, p->name(),context);
if (fld) {
ExpOperation* op = YOBJECT(ExpOperation,fld);
XDebug(DebugAll,"Field '%s' is %s",fld->name().c_str(),
(op ? (YOBJECT(ExpFunction,op) ? "function" :
(YOBJECT(ExpWrapper,op) ? "object" : "operation")) : "string"));
if (op)
ok = runAssign(stack, *op, context) && ok;
else
ok = runAssign(stack, ExpOperation(*fld,fld->name()), context) && ok;
}
else
ok = false;
}
return ok;
}
#define MAKE_NAME(x) { #x, ScriptRun::x }
static const TokenDict s_states[] = {
MAKE_NAME(Invalid),

View File

@ -1099,6 +1099,15 @@ public:
*/
virtual bool runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context);
/**
* Copy all fields from another context
* @param stack Evaluation stack in use
* @param original Script context to copy from
* @param context Pointer to context data passed from evaluation methods
* @return True if all fields were copied
*/
virtual bool copyFields(ObjList& stack, const ScriptContext& original, GenObject* context);
private:
NamedList m_params;
};
@ -1391,6 +1400,21 @@ public:
virtual Mutex* mutex()
{ return m_mutex; }
/**
* Clone and rename method
* @param name Name of the cloned object
* @return New object instance
*/
virtual JsObject* clone(const char* name) const
{ return new JsObject(m_mutex,name); }
/**
* Clone method
* @return New object instance
*/
inline JsObject* clone() const
{ return clone(toString()); }
/**
* Try to evaluate a single method
* @param stack Evaluation stack in use, parameters are popped off this stack
@ -1447,6 +1471,14 @@ public:
static void initialize(ScriptContext* context);
protected:
/**
* Constructor for an empty object
* @param mtx Pointer to the mutex that serializes this object
* @param name Full name of the object
* @param frozen True if the object is to be frozen from creation
*/
JsObject(Mutex* mtx, const char* name, bool frozen = false);
/**
* Try to evaluate a single native method
* @param stack Evaluation stack in use, parameters are popped off this stack
@ -1457,6 +1489,13 @@ protected:
*/
virtual bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context);
/**
* Retrieve the Mutex object used to serialize object access
* @return Pointer to the mutex of the context this object belongs to
*/
inline Mutex* mutex() const
{ return m_mutex; }
private:
bool m_frozen;
Mutex* m_mutex;
@ -1477,6 +1516,13 @@ public:
*/
JsFunction(Mutex* mtx = 0);
/**
* Constructor with function name
* @param mtx Pointer to the mutex that serializes this object
* @param name Name of the function
*/
JsFunction(Mutex* mtx, const char* name);
/**
* Try to evaluate a single user defined method
* @param stack Evaluation stack in use, parameters are popped off this stack
@ -1498,6 +1544,8 @@ protected:
*/
virtual bool runNative(ObjList& stack, const ExpOperation& oper, GenObject* context);
private:
void init();
};
/**