Added string properties and methods that apply to all non-JS objects.

Fixed the name resolution to allow the pseudo properties.


git-svn-id: http://yate.null.ro/svn/yate/trunk@5081 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-05-30 17:48:13 +00:00
parent 24670814da
commit 7b7b3abdf9
5 changed files with 147 additions and 4 deletions

View File

@ -886,6 +886,8 @@ ExpOperation* ExpEvaluator::popValue(ObjList& stack, GenObject* context) const
ExpOperation* oper = popOne(stack);
if (!oper || (oper->opcode() != OpcField))
return oper;
XDebug(DebugAll,"ExpEvaluator::popValue() field '%s' [%p]",
oper->name().c_str(),this);
bool ok = runField(stack,*oper,context);
TelEngine::destruct(oper);
return ok ? popOne(stack) : 0;

View File

@ -45,6 +45,8 @@ public:
private:
GenObject* resolveTop(ObjList& stack, const String& name, GenObject* context);
GenObject* resolve(ObjList& stack, String& name, GenObject* context);
bool runStringFunction(GenObject* obj, const String& name, ObjList& stack, const ExpOperation& oper, GenObject* context);
bool runStringField(GenObject* obj, const String& name, ObjList& stack, const ExpOperation& oper, GenObject* context);
};
class JsNull : public JsObject
@ -301,6 +303,8 @@ bool JsContext::runFunction(ObjList& stack, const ExpOperation& oper, GenObject*
ExpOperation op(oper,name);
return ext->runFunction(stack,op,context);
}
if (runStringFunction(o,name,stack,oper,context))
return true;
}
if (name == YSTRING("isNaN")) {
bool nan = true;
@ -343,10 +347,105 @@ bool JsContext::runField(ObjList& stack, const ExpOperation& oper, GenObject* co
ExpOperation op(oper,name);
return ext->runField(stack,op,context);
}
if (runStringField(o,name,stack,oper,context))
return true;
}
return JsObject::runField(stack,oper,context);
}
bool JsContext::runStringFunction(GenObject* obj, const String& name, ObjList& stack, const ExpOperation& oper, GenObject* context)
{
const String* str = YOBJECT(String,obj);
if (!str)
return false;
if (name == YSTRING("charAt")) {
int idx = 0;
ObjList args;
if (extractArgs(stack,oper,context,args)) {
ExpOperation* op = static_cast<ExpOperation*>(args[0]);
if (op && op->isInteger())
idx = op->number();
}
ExpEvaluator::pushOne(stack,new ExpOperation(String(str->at(idx))));
return true;
}
if (name == YSTRING("indexOf")) {
int idx = -1;
ObjList args;
if (extractArgs(stack,oper,context,args)) {
const String* what = static_cast<String*>(args[0]);
if (what) {
ExpOperation* from = static_cast<ExpOperation*>(args[1]);
int offs = (from && from->isInteger()) ? from->number() : 0;
if (offs < 0)
offs = 0;
idx = str->find(*what,offs);
}
}
ExpEvaluator::pushOne(stack,new ExpOperation((long int)idx));
return true;
}
if (name == YSTRING("substr")) {
ObjList args;
int offs = 0;
int len = -1;
if (extractArgs(stack,oper,context,args)) {
ExpOperation* op = static_cast<ExpOperation*>(args[0]);
if (op && op->isInteger())
offs = op->number();
op = static_cast<ExpOperation*>(args[1]);
if (op && op->isInteger()) {
len = op->number();
if (len < 0)
len = 0;
}
}
ExpEvaluator::pushOne(stack,new ExpOperation(str->substr(offs,len)));
return true;
}
if (name == YSTRING("match")) {
ObjList args;
String buf(*str);
if (extractArgs(stack,oper,context,args)) {
ExpOperation* op = static_cast<ExpOperation*>(args[0]);
ExpWrapper* wrap = YOBJECT(ExpWrapper,op);
JsRegExp* rexp = YOBJECT(JsRegExp,wrap);
bool ok = false;
if (rexp)
ok = buf.matches(rexp->regexp());
else if (!wrap) {
Regexp r(*static_cast<String*>(op),true);
ok = buf.matches(r);
}
if (ok) {
JsArray* jsa = new JsArray(mutex());
for (int i = 0; i <= buf.matchCount(); i++)
jsa->push(new ExpOperation(buf.matchString(i)));
jsa->params().addParam(new ExpOperation((long int)buf.matchOffset(),"index"));
if (rexp)
jsa->params().addParam(wrap->clone("input"));
ExpEvaluator::pushOne(stack,new ExpWrapper(jsa));
return true;
}
}
ExpEvaluator::pushOne(stack,s_null.ExpOperation::clone());
return true;
}
return false;
}
bool JsContext::runStringField(GenObject* obj, const String& name, ObjList& stack, const ExpOperation& oper, GenObject* context)
{
const String* s = YOBJECT(String,obj);
if (!s)
return false;
if (name == YSTRING("length")) {
ExpEvaluator::pushOne(stack,new ExpOperation((long int)s->length()));
return true;
}
return false;
}
bool JsContext::runAssign(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
XDebug(DebugAll,"JsContext::runAssign '%s'='%s' [%p]",oper.name().c_str(),oper.c_str(),this);

View File

@ -123,26 +123,33 @@ static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int dep
buf.append(str,"\r\n");
return;
}
seen.append(obj)->setDelete(false);
const NamedString* nstr = YOBJECT(NamedString,obj);
const NamedPointer* nptr = YOBJECT(NamedPointer,nstr);
const char* type = nstr ? (nptr ? "NamedPointer" : "NamedString") : "???";
const ScriptContext* scr = YOBJECT(ScriptContext,obj);
const ExpWrapper* wrap = 0;
bool objRecursed = false;
if (scr) {
if (YOBJECT(JsObject,scr)) {
const JsObject* jso = YOBJECT(JsObject,scr);
if (jso) {
objRecursed = (seen.find(jso) != 0);
if ((jso != obj) && !objRecursed)
seen.append(jso)->setDelete(false);
if (YOBJECT(JsArray,scr))
type = "JsArray";
else if (YOBJECT(JsFunction,scr))
type = "JsFunction";
else if (YOBJECT(JsRegExp,scr))
type = "JsRegExp";
else
type = "JsObject";
}
else
type = "ScriptContext";
}
seen.append(obj)->setDelete(false);
const ExpOperation* exp = YOBJECT(ExpOperation,nstr);
if (exp) {
if (exp && !scr) {
if ((wrap = YOBJECT(ExpWrapper,exp)))
type = wrap->object() ? "ExpWrapper" : "Undefined";
else if (YOBJECT(ExpFunction,exp))
@ -155,7 +162,11 @@ static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int dep
else
str << "'" << obj->toString() << "'";
str << " (" << type << ")";
if (objRecursed)
str << " (already seen)";
buf.append(str,"\r\n");
if (objRecursed)
return;
str.clear();
if (scr) {
NamedIterator iter(scr->params());
@ -309,7 +320,9 @@ ExpOperation* JsObject::popValue(ObjList& stack, GenObject* context)
ExpOperation* oper = ExpEvaluator::popOne(stack);
if (!oper || (oper->opcode() != ExpEvaluator::OpcField))
return oper;
bool ok = runField(stack,*oper,context);
XDebug(DebugAll,"JsObject::popValue() field '%s' in '%s' [%p]",
oper->name().c_str(),toString().c_str(),this);
bool ok = runMatchingField(stack,*oper,context);
TelEngine::destruct(oper);
return ok ? ExpEvaluator::popOne(stack) : 0;
}

View File

@ -133,6 +133,26 @@ bool ScriptContext::runAssign(ObjList& stack, const ExpOperation& oper, GenObjec
return true;
}
bool ScriptContext::runMatchingField(ObjList& stack, const ExpOperation& oper, GenObject* context)
{
ExpExtender* ext = this;
if (!hasField(stack,oper,context)) {
ext = 0;
for (ObjList* l = stack.skipNull(); l; l = l->skipNext()) {
ext = YOBJECT(ExpExtender,l->get());
if (ext && ext->hasField(stack,oper,context))
break;
ext = 0;
}
}
if (!ext) {
ScriptRun* run = YOBJECT(ScriptRun,context);
if (run)
ext = run->context();
}
return ext && ext->runField(stack,oper,context);
}
bool ScriptContext::copyFields(ObjList& stack, const ScriptContext& original, GenObject* context)
{
bool ok = true;

View File

@ -1216,6 +1216,15 @@ public:
*/
virtual bool copyFields(ObjList& stack, const ScriptContext& original, GenObject* context);
/**
* Try to evaluate a single field searching for a matching context
* @param stack Evaluation stack in use, field value must be pushed on it
* @param oper Field to evaluate
* @param context Pointer to context data passed from evaluation methods
* @return True if evaluation succeeded
*/
bool runMatchingField(ObjList& stack, const ExpOperation& oper, GenObject* context);
private:
NamedList m_params;
};