diff --git a/libs/yscript/jsobjects.cpp b/libs/yscript/jsobjects.cpp index b7d921c9..1812dd1b 100644 --- a/libs/yscript/jsobjects.cpp +++ b/libs/yscript/jsobjects.cpp @@ -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()); } diff --git a/libs/yscript/yatescript.h b/libs/yscript/yatescript.h index 973cd4b6..374ee74a 100644 --- a/libs/yscript/yatescript.h +++ b/libs/yscript/yatescript.h @@ -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 diff --git a/modules/javascript.cpp b/modules/javascript.cpp index f0c9d511..7048ed71 100644 --- a/modules/javascript.cpp +++ b/modules/javascript.cpp @@ -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;