static EjsString *serialize(Ejs *ejs, EjsAny *vp, Json *json) { EjsName qname; EjsFunction *fn; EjsString *result, *sv; EjsTrait *trait; EjsObj *pp, *obj, *replacerArgs[2]; wchar *cp; cchar *key; int c, isArray, i, count, slotNum, quotes; /* The main code below can handle Arrays, Objects, objects derrived from Object and also native classes with properties. All others just use toString. */ count = ejsIsPot(ejs, vp) ? ejsGetLength(ejs, vp) : 0; if (count == 0 && TYPE(vp) != ESV(Object) && TYPE(vp) != ESV(Array)) { // OPT - need some flag for this test. if (!ejsIsDefined(ejs, vp) || ejsIs(ejs, vp, Boolean) || ejsIs(ejs, vp, Number)) { return ejsToString(ejs, vp); } else if (json->regexp) { return ejsToString(ejs, vp); } else { return ejsToLiteralString(ejs, vp); } } obj = vp; json->nest++; if (json->buf == 0) { json->buf = mprCreateBuf(0, 0); mprAddRoot(json->buf); } isArray = ejsIs(ejs, vp, Array); mprPutCharToWideBuf(json->buf, isArray ? '[' : '{'); if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } if (++ejs->serializeDepth <= json->depth && !VISITED(obj)) { SET_VISITED(obj, 1); for (slotNum = 0; slotNum < count && !ejs->exception; slotNum++) { trait = ejsGetPropertyTraits(ejs, obj, slotNum); if (trait && (trait->attributes & (EJS_TRAIT_HIDDEN | EJS_TRAIT_DELETED | EJS_FUN_INITIALIZER | EJS_FUN_MODULE_INITIALIZER)) && !json->hidden) { continue; } pp = ejsGetProperty(ejs, obj, slotNum); if (ejs->exception) { SET_VISITED(obj, 0); json->nest--; return 0; } if (pp == 0) { continue; } if (isArray) { key = itos(slotNum); qname.name = ejsCreateStringFromAsc(ejs, key); qname.space = ESV(empty); } else { qname = ejsGetPropertyName(ejs, vp, slotNum); } quotes = json->quotes; if (!quotes) { // UNICODE for (cp = qname.name->value; cp < &qname.name->value[qname.name->length]; cp++) { if (!isalnum((uchar) *cp) && *cp != '_') { quotes = 1; break; } } } if (json->pretty) { for (i = 0; i < ejs->serializeDepth; i++) { mprPutStringToWideBuf(json->buf, json->indent); } } if (!isArray) { if (json->namespaces) { if (qname.space != ESV(empty)) { mprPutToBuf(json->buf, "\"%@\"::", qname.space); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } for (cp = qname.name->value; cp && *cp; cp++) { c = *cp; if (c == '"' || c == '\\') { mprPutCharToWideBuf(json->buf, '\\'); mprPutCharToWideBuf(json->buf, c); } else { mprPutCharToWideBuf(json->buf, c); } } if (quotes) { mprPutCharToWideBuf(json->buf, '"'); } mprPutCharToWideBuf(json->buf, ':'); if (json->pretty) { mprPutCharToWideBuf(json->buf, ' '); } } fn = (EjsFunction*) ejsGetPropertyByName(ejs, TYPE(pp)->prototype, N(NULL, "toJSON")); // OPT - check that this is going directly to serialize most of the time if (!ejsIsFunction(ejs, fn) || (fn->isNativeProc && fn->body.proc == (EjsProc) ejsObjToJSON)) { sv = serialize(ejs, pp, json); } else { sv = (EjsString*) ejsRunFunction(ejs, fn, pp, 1, &json->options); } if (sv == 0 || !ejsIs(ejs, sv, String)) { if (ejs->exception) { ejsThrowTypeError(ejs, "Cannot serialize property %@", qname.name); SET_VISITED(obj, 0); return 0; } } else { if (json->replacer) { replacerArgs[0] = (EjsObj*) qname.name; replacerArgs[1] = (EjsObj*) sv; /* function replacer(key: String, value: String): String */ sv = ejsRunFunction(ejs, json->replacer, obj, 2, (EjsObj**) replacerArgs); } mprPutBlockToBuf(json->buf, sv->value, sv->length * sizeof(wchar)); } if ((slotNum + 1) < count || json->commas) { mprPutCharToWideBuf(json->buf, ','); } if (json->pretty) { mprPutCharToWideBuf(json->buf, '\n'); } } SET_VISITED(obj, 0); } --ejs->serializeDepth; if (json->pretty) { for (i = ejs->serializeDepth; i > 0; i--) { mprPutStringToWideBuf(json->buf, json->indent); } } mprPutCharToWideBuf(json->buf, isArray ? ']' : '}'); mprAddNullToWideBuf(json->buf); if (--json->nest == 0) { result = ejsCreateString(ejs, mprGetBufStart(json->buf), mprGetBufLength(json->buf) / sizeof(wchar)); mprRemoveRoot(json->buf); } else { result = 0; } return result; }
/* List the various property slot assignments */ static void lstSlotAssignments(EjsMod *mp, EjsModule *module, EjsObj *parent, int slotNum, EjsObj *obj) { Ejs *ejs; EjsTrait *trait; EjsType *type; EjsObj *vp; EjsPot *prototype; EjsFunction *fun; EjsBlock *block; EjsName qname; int i, numInherited, count; mprAssert(obj); mprAssert(module); ejs = mp->ejs; if (VISITED(obj)) { return; } SET_VISITED(obj, 1); if (obj == ejs->global) { mprFprintf(mp->file, "\n#\n" "# Global slot assignments (Num prop %d)\n" "#\n", ejsGetLength(ejs, obj)); /* List slots for global */ for (i = module->firstGlobal; i < module->lastGlobal; i++) { trait = ejsGetPropertyTraits(ejs, ejs->global, i); qname = ejsGetPropertyName(ejs, ejs->global, i); if (qname.name == 0) { continue; } lstVarSlot(mp, module, &qname, trait, i); } /* List slots for the initializer */ fun = (EjsFunction*) module->initializer; if (fun) { mprFprintf(mp->file, "\n#\n" "# Initializer slot assignments (Num prop %d)\n" "#\n", ejsGetLength(ejs, (EjsObj*) fun)); count = ejsGetLength(ejs, (EjsObj*) fun); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, (EjsObj*) fun, i); qname = ejsGetPropertyName(ejs, (EjsObj*) fun, i); if (qname.name == 0) { continue; } mprAssert(trait); lstVarSlot(mp, module, &qname, trait, i); } } } else if (ejsIsFunction(ejs, obj)) { fun = (EjsFunction*) obj; count = ejsGetLength(ejs, (EjsObj*) obj); if (count > 0) { mprFprintf(mp->file, "\n#\n" "# Local slot assignments for the \"%@\" function (Num slots %d)\n" "#\n", fun->name, count); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, obj, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, obj, i); lstVarSlot(mp, module, &qname, trait, i); } } } else if (ejsIsType(ejs, obj)) { /* Types */ type = (EjsType*) obj; mprFprintf(mp->file, "\n#\n" "# Class slot assignments for the \"%@\" class (Num slots %d)\n" "#\n", type->qname.name, ejsGetLength(ejs, (EjsObj*) type)); count = ejsGetLength(ejs, (EjsObj*) type); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, (EjsObj*) type, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, obj, i); lstVarSlot(mp, module, &qname, trait, i); } prototype = type->prototype; if (type->baseType && type->baseType->prototype) { numInherited = ejsGetLength(ejs, type->baseType->prototype); } else { numInherited = 0; } mprFprintf(mp->file, "\n#\n" "# Instance slot assignments for the \"%@\" class (Num prop %d, num inherited %d)\n" "#\n", type->qname.name, prototype ? ejsGetLength(ejs, prototype): 0, numInherited); if (prototype) { count = ejsGetLength(ejs, prototype); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, prototype, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, prototype, i); if (qname.name) { lstVarSlot(mp, module, &qname, trait, i); } } } } else if (ejsIsBlock(ejs, obj)) { qname = ejsGetPropertyName(ejs, parent, slotNum); block = (EjsBlock*) obj; count = ejsGetLength(ejs, (EjsObj*) block); if (count > 0) { mprFprintf(mp->file, "\n#\n" "# Block slot assignments for the \"%@\" (Num slots %d)\n" "#\n", qname.name, ejsGetLength(ejs, obj)); count = ejsGetLength(ejs, obj); for (i = 0; i < count; i++) { trait = ejsGetPropertyTraits(ejs, obj, i); mprAssert(trait); qname = ejsGetPropertyName(ejs, obj, i); lstVarSlot(mp, module, &qname, trait, i); } } } /* Now recurse on types, functions and blocks */ if (obj == ejs->global) { i = module->firstGlobal; count = module->lastGlobal; } else { i = 0; count = ejsGetLength(ejs, obj); } for (; i < count; i++) { qname = ejsGetPropertyName(ejs, obj, i); vp = ejsGetProperty(ejs, obj, i); if (vp == 0) { continue; } if (ejsIsType(ejs, vp) || ejsIsFunction(ejs, vp) || ejsIsBlock(ejs, vp)) { lstSlotAssignments(mp, module, obj, i, vp); } } SET_VISITED(obj, 0); }
/* Find a variable in an object considering namespaces. If the space is "", then search for the property name using the set of open namespaces. */ int ejsLookupVarWithNamespaces(Ejs *ejs, EjsAny *obj, EjsName name, EjsLookup *lookup) { EjsNamespace *nsp; EjsName qname, target; EjsString *space; EjsBlock *b; MprList *globalSpaces; int next, slotNum; assert(obj); assert(name.name); assert(name.space); assert(lookup); b = (EjsBlock*) ejs->global; globalSpaces = &b->namespaces; if (name.space->value[0]) { /* Lookup with an explicit namespace */ slotNum = ejsLookupProperty(ejs, obj, name); lookup->name = name; } else { /* Lookup with the set of open namespaces in the current scope Special lookup with space == NULL. Means lookup only match if there is only one property of this name */ qname.space = NULL; qname.name = name.name; if ((slotNum = ejsLookupProperty(ejs, obj, qname)) >= 0) { if (TYPE(obj)->virtualSlots) { lookup->name = name; } else { target = ejsGetPropertyName(ejs, obj, slotNum); lookup->name = target; space = name.space; if (space->value[0] && space != target.space) { /* Unique name match. Name matches, but namespace does not */ slotNum = -1; } else if (target.space && target.space->value[0]) { /* OPT - Look at global spaces first */ for (next = -1; (nsp = mprGetPrevItem(globalSpaces, &next)) != 0; ) { if (nsp->value == target.space) { goto done; } } // OPT -- need a fast way to know if the space is a standard reserved namespace or not */ /* Verify namespace is open */ for (b = ejs->state->bp; b; b = b->scope) { // OPT. Doing some namespaces multiple times. Fix in compiler. for (next = -1; (nsp = mprGetPrevItem(&b->namespaces, &next)) != 0; ) { if (nsp->value == target.space) { goto done; } } } slotNum = -1; } } } else { qname = name; for (b = ejs->state->bp; b; b = b->scope) { for (next = -1; (nsp = (EjsNamespace*) mprGetPrevItem(&b->namespaces, &next)) != 0; ) { qname.space = nsp->value; if ((slotNum = ejsLookupProperty(ejs, obj, qname)) >= 0) { lookup->name = qname; goto done; } } } for (next = -1; (nsp = mprGetPrevItem(globalSpaces, &next)) != 0; ) { qname.space = nsp->value; if ((slotNum = ejsLookupProperty(ejs, obj, qname)) >= 0) { lookup->name = qname; goto done; } } } } done: if (slotNum >= 0) { // OPT MUST GET RID OF THIS. Means that every store does a get lookup->ref = ejsGetProperty(ejs, obj, slotNum); if (ejs->exception) { slotNum = -1; } else { lookup->obj = obj; lookup->slotNum = slotNum; lookup->trait = ejsGetPropertyTraits(ejs, lookup->obj, lookup->slotNum); } } return slotNum; }
static void lstFunction(EjsMod *mp, EjsModule *module, EjsObj *block, int slotNum, EjsName qname, EjsFunction *fun, int attributes) { Ejs *ejs; EjsTrait *trait; EjsName lname; EjsType *resultType; EjsPot *activation; EjsString *space, *blockName; int i, numLocals, numProp; ejs = mp->ejs; activation = fun->activation; numProp = activation ? activation->numProp : 0; space = mapSpace(ejs, qname.space); mprFprintf(mp->file, "\nFUNCTION: "); /* Do the function declaration */ if (attributes) { if (slotNum < 0) { /* Special just for global initializers */ mprFprintf(mp->file, "[initializer] %@ %sfunction %@(", space, getAttributeString(mp, attributes), qname.name); } else { blockName = getBlockName(mp, block, slotNum); mprFprintf(mp->file, "[%@-%02d] %@ %sfunction %@(", blockName, slotNum, space, getAttributeString(mp, attributes), qname.name); } } else { blockName = getBlockName(mp, block, slotNum); mprFprintf(mp->file, "[%@-%02d] %@ function %@(", blockName, slotNum, space, qname.name); } for (i = 0; i < (int) fun->numArgs; ) { lname = ejsGetPropertyName(ejs, activation, i); trait = ejsGetPropertyTraits(ejs, activation, i); if (trait->type) { mprFprintf(mp->file, "%@: %@", lname.name, trait->type->qname.name); } else { mprFprintf(mp->file, "%@", lname.name); } if (++i < (int) fun->numArgs) { mprFprintf(mp->file, ", "); } } resultType = fun->resultType; mprFprintf(mp->file, ") : %@\n", resultType ? resultType->qname.name : EST(Void)->qname.name); /* Repeat the args */ for (i = 0; i < (int) fun->numArgs; i++) { lname = ejsGetPropertyName(ejs, activation, i); trait = ejsGetPropertyTraits(ejs, activation, i); mprFprintf(mp->file, " ARG: [arg-%02d] %@ %@", i, lname.space, lname.name); if (trait->type) { mprFprintf(mp->file, " : %@", trait->type->qname.name); } mprFprintf(mp->file, "\n"); } numLocals = numProp - fun->numArgs; for (i = 0; i < numLocals; i++) { lname = ejsGetPropertyName(ejs, activation, i + fun->numArgs); trait = ejsGetPropertyTraits(ejs, activation, i + fun->numArgs); mprFprintf(mp->file, " LOCAL: [local-%02d] var %@", i + fun->numArgs, lname.name); if (trait->type) { mprFprintf(mp->file, " : %@", trait->type->qname.name); } mprFprintf(mp->file, "\n"); } if (fun->body.code) { mprFprintf(mp->file, "\n"); interp(mp, module, fun); } mprFprintf(mp->file, "\n"); }