Added print/dump_r functions used to print/dump a specific variable or script context using flags to filter what to print: props only (default), funcs only ...

git-svn-id: http://voip.null.ro/svn/yate@6437 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2020-10-14 10:38:31 +00:00
parent 41c8c9a632
commit a51728652e
3 changed files with 148 additions and 18 deletions

View File

@ -125,10 +125,17 @@ protected:
// Helper function that does the actual object printing
static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int depth, ObjList& seen)
static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int depth, ObjList& seen,
unsigned int flags)
{
if (!obj)
return;
if (depth > 1 && !(flags & JsObject::DumpRecursive))
return;
// Check if we have something to dump
unsigned int dump = flags & (JsObject::DumpFunc | JsObject::DumpProp);
if (!dump)
return;
String str(' ',2 * depth);
if (seen.find(obj)) {
str << "(recursivity encountered)";
@ -136,12 +143,17 @@ static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int dep
return;
}
const NamedString* nstr = YOBJECT(NamedString,obj);
// Check for prototype dump (always dump the first level if original object is a prototype)
bool isProto = nstr && nstr->name() == JsObject::protoName();
if (depth && isProto && !(flags & JsObject::DumpProto))
return;
const NamedPointer* nptr = YOBJECT(NamedPointer,nstr);
const char* type = nstr ? (nptr ? "NamedPointer" : "NamedString") : "???";
const char* subType = 0;
const ScriptContext* scr = YOBJECT(ScriptContext,obj);
const ExpWrapper* wrap = 0;
bool objRecursed = false;
bool isFunc = false;
if (scr) {
const JsObject* jso = YOBJECT(JsObject,scr);
if (jso) {
@ -150,8 +162,10 @@ static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int dep
seen.append(jso)->setDelete(false);
if (YOBJECT(JsArray,scr))
type = "JsArray";
else if (YOBJECT(JsFunction,scr))
else if (YOBJECT(JsFunction,scr)) {
type = "JsFunction";
isFunc = true;
}
else if (YOBJECT(JsRegExp,scr))
type = "JsRegExp";
else if (YOBJECT(JsDate,scr))
@ -167,38 +181,79 @@ static void dumpRecursiveObj(const GenObject* obj, String& buf, unsigned int dep
if (exp && !scr) {
if ((wrap = YOBJECT(ExpWrapper,exp)))
type = wrap->object() ? "ExpWrapper" : "Undefined";
else if (YOBJECT(ExpFunction,exp))
else if (YOBJECT(ExpFunction,exp)) {
type = "ExpFunction";
isFunc = true;
}
else {
type = "ExpOperation";
subType = exp->typeOf();
}
}
if (nstr)
str << "'" << nstr->name() << "' = '" << *nstr << "'";
// Check for func/prop dump (don't do it if we are printing a prototype)
if (depth && !isProto && ((isFunc && (0 == (flags & JsObject::DumpFunc))) ||
(!isFunc && (0 == (flags & JsObject::DumpProp)))))
return;
bool dumpType = flags & JsObject::DumpType;
if (nstr) {
str << "'" << nstr->name() << "'";
// Nicely dump property value if dumping props only and type is not shown
if ((dump == JsObject::DumpProp) && !isProto && !dumpType) {
if (scr) {
if (exp && JsParser::isNull(*exp))
str << " = null";
else if (YOBJECT(JsRegExp,scr))
str << " = /" << *nstr << "/";
else if (flags & JsObject::DumpPropObjType) {
if (YOBJECT(JsObject,scr))
str << " = " << *nstr;
else
str << " = [ScriptContext]";
}
}
else if (exp) {
if (JsParser::isUndefined(*exp))
str << " = undefined";
else if (exp->isInteger()) {
if (exp->isBoolean())
str << " = " << exp->valBoolean();
else
str << " = " << exp->number();
}
else if (exp->isNumber()) // NaN
str << " = " << *nstr;
else // string
str << " = '" << *nstr << "'";
}
else
str << " = '" << *nstr << "'";
}
else
str << " = '" << *nstr << "'";
}
else
str << "'" << obj->toString() << "'";
str << " (" << type << (subType ? ", " : "") << subType << ")";
if (dumpType)
str << " (" << type << (subType ? ", " : "") << subType << ")";
if (objRecursed)
str << " (already seen)";
buf.append(str,"\r\n");
if (objRecursed)
return;
str.clear();
if (scr) {
NamedIterator iter(scr->params());
while (const NamedString* p = iter.get())
dumpRecursiveObj(p,buf,depth + 1,seen);
dumpRecursiveObj(p,buf,depth + 1,seen,flags);
if (scr->nativeParams()) {
iter = *scr->nativeParams();
while (const NamedString* p = iter.get())
dumpRecursiveObj(p,buf,depth + 1,seen);
dumpRecursiveObj(p,buf,depth + 1,seen,flags);
}
}
else if (wrap)
dumpRecursiveObj(wrap->object(),buf,depth + 1,seen);
dumpRecursiveObj(wrap->object(),buf,depth + 1,seen,flags);
else if (nptr)
dumpRecursiveObj(nptr->userData(),buf,depth + 1,seen);
dumpRecursiveObj(nptr->userData(),buf,depth + 1,seen,flags);
}
@ -243,16 +298,16 @@ JsObject* JsObject::copy(Mutex* mtx) const
return jso;
}
void JsObject::dumpRecursive(const GenObject* obj, String& buf)
void JsObject::dumpRecursive(const GenObject* obj, String& buf, unsigned int flags)
{
ObjList seen;
dumpRecursiveObj(obj,buf,0,seen);
dumpRecursiveObj(obj,buf,0,seen,flags);
}
void JsObject::printRecursive(const GenObject* obj)
void JsObject::printRecursive(const GenObject* obj, unsigned int flags)
{
String buf;
dumpRecursive(obj,buf);
dumpRecursive(obj,buf,flags);
Output("%s",buf.c_str());
}

View File

@ -1954,6 +1954,21 @@ class YSCRIPT_API JsObject : public ScriptContext
friend class JsFunction;
YCLASS(JsObject,ScriptContext)
public:
/**
* Dump object flags
*/
enum DumpFlags {
DumpFunc = 0x01, // Dump functions
DumpProp = 0x02, // Dump non functions (data)
DumpRecursive = 0x10, // Dump recursive (stop on root if not set)
DumpType = 0x20, // Dump type (apply to functions also),
DumpProto = 0x40, // Dump prototype
DumpPropObjType = 0x80, // Dump non basic type for DumpPropOnly whithout DumpType
// Masks
DumpFuncOnly = DumpRecursive | DumpProto | DumpFunc,
DumpPropOnly = DumpRecursive | DumpPropObjType | DumpProp,
};
/**
* Constructor
* @param name Name of the object
@ -2276,14 +2291,16 @@ public:
* Helper method to return the hierarchical structure of an object
* @param obj Object to dump structure
* @param buf String to which the structure is added
* @param flags Flags indicating what to dump
*/
static void dumpRecursive(const GenObject* obj, String& buf);
static void dumpRecursive(const GenObject* obj, String& buf, unsigned int flags = 0xffffffff);
/**
* Helper method to display the hierarchical structure of an object
* @param obj Object to display
* @param flags Flags indicating what to dump (display)
*/
static void printRecursive(const GenObject* obj);
static void printRecursive(const GenObject* obj, unsigned int flags = 0xffffffff);
/**
* Static method to obtain a JSON representation of the given object

View File

@ -362,6 +362,7 @@ private:
#define MKDEBUG(lvl) params().addParam(new ExpOperation((int64_t)Debug ## lvl,"Debug" # lvl))
#define MKTIME(typ) params().addParam(new ExpOperation((int64_t)SysUsage:: typ ## Time,# typ "Time"))
#define MKDUMP(typ) params().addParam(new ExpOperation((int64_t)JsObject:: Dump ## typ,"Dump" # typ))
class JsEngine : public JsObject, public DebugEnabler
{
YCLASS(JsEngine,JsObject)
@ -387,6 +388,14 @@ public:
MKTIME(Wall);
MKTIME(User);
MKTIME(Kernel);
MKDUMP(PropOnly),
MKDUMP(FuncOnly),
MKDUMP(Func),
MKDUMP(Prop),
MKDUMP(Recursive),
MKDUMP(Type),
MKDUMP(Proto),
MKDUMP(PropObjType),
params().addParam(new ExpFunction("output"));
params().addParam(new ExpFunction("debug"));
params().addParam(new ExpFunction("traceDebug"));
@ -405,6 +414,10 @@ public:
params().addParam(new ExpFunction("init"));
params().addParam(new ExpFunction("dump_r"));
params().addParam(new ExpFunction("print_r"));
params().addParam(new ExpFunction("dump_var_r"));
params().addParam(new ExpFunction("print_var_r"));
params().addParam(new ExpFunction("dump_root_r"));
params().addParam(new ExpFunction("print_root_r"));
params().addParam(new ExpFunction("dump_t"));
params().addParam(new ExpFunction("print_t"));
params().addParam(new ExpFunction("debugName"));
@ -1185,7 +1198,7 @@ static void dumpTable(const ExpOperation& oper, String& str, const char* eol)
// Return false if the number of arguments is not the expected one
static bool extractStackArgs(int minArgc, JsObject* obj,
ObjList& stack, const ExpOperation& oper, GenObject* context, ObjList& args,
ExpOperation** op1, ExpOperation** op2, ExpOperation** op3 = 0)
ExpOperation** op1, ExpOperation** op2 = 0, ExpOperation** op3 = 0)
{
if (!obj)
return false;
@ -1204,6 +1217,9 @@ static bool extractStackArgs(int minArgc, JsObject* obj,
EXTRACT_ARG_CHECK(op1,1);
return true;
#undef EXTRACT_ARG_CHECK
case 0:
if (!minArgc)
return true;
}
return false;
}
@ -1517,6 +1533,48 @@ bool JsEngine::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
else
return false;
}
else if (oper.name() == YSTRING("dump_var_r")) {
// str = Engine.dump_var_r(obj[,flags])
ObjList args;
ExpOperation* obj = 0;
ExpOperation* flags = 0;
if (!extractStackArgs(1,this,stack,oper,context,args,&obj,&flags))
return false;
String buf;
dumpRecursive(obj,buf,flags ? flags->valInteger(DumpPropOnly) : DumpPropOnly);
ExpEvaluator::pushOne(stack,new ExpOperation(buf));
}
else if (oper.name() == YSTRING("print_var_r")) {
// Engine.print_var_r(obj[,flags])
ObjList args;
ExpOperation* obj = 0;
ExpOperation* flags = 0;
if (!extractStackArgs(1,this,stack,oper,context,args,&obj,&flags))
return false;
printRecursive(obj,flags ? flags->valInteger(DumpPropOnly) : DumpPropOnly);
}
else if (oper.name() == YSTRING("dump_root_r")) {
// str = Engine.dump_root_r([flags])
ObjList args;
ExpOperation* flags = 0;
if (!extractStackArgs(0,this,stack,oper,context,args,&flags))
return false;
String buf;
ScriptRun* run = YOBJECT(ScriptRun,context);
dumpRecursive(run ? run->context() : context,buf,
flags ? flags->valInteger(DumpPropOnly) : DumpPropOnly);
ExpEvaluator::pushOne(stack,new ExpOperation(buf));
}
else if (oper.name() == YSTRING("print_root_r")) {
// Engine.print_root_r([flags])
ObjList args;
ExpOperation* flags = 0;
if (!extractStackArgs(0,this,stack,oper,context,args,&flags))
return false;
ScriptRun* run = YOBJECT(ScriptRun,context);
printRecursive(run ? run->context() : context,
flags ? flags->valInteger(DumpPropOnly) : DumpPropOnly);
}
else if (oper.name() == YSTRING("dump_t")) {
if (oper.number() != 1)
return false;