/* * Format the stack backtrace */ char *ejsFormatStack(Ejs *ejs) { EjsFrame *frame; EjsType *type; EjsFunction *fun; cchar *typeName, *functionName, *line, *typeSep, *codeSep; char *backtrace, *traceLine; int level, len; mprAssert(ejs); backtrace = 0; len = 0; level = 0; for (frame = ejs->frame; frame; frame = frame->caller) { if (frame->currentLine == 0) { line = ""; } else { for (line = frame->currentLine; *line && isspace((int) *line); line++) { ; } } typeName = ""; functionName = "global"; fun = &frame->function; if (fun) { if (fun->owner) { functionName = ejsGetPropertyName(ejs, fun->owner, fun->slotNum).name; } if (ejsIsType(fun->owner)) { type = (EjsType*) fun->owner; if (type) { typeName = type->qname.name; } } } typeSep = (*typeName) ? "." : ""; codeSep = (*line) ? "->" : ""; if (mprAllocSprintf(ejs, &traceLine, MPR_MAX_STRING, " [%02d] %s, %s%s%s, line %d %s %s\n", level++, frame->fileName ? frame->fileName : "script", typeName, typeSep, functionName, frame->lineNumber, codeSep, line) < 0) { break; } backtrace = (char*) mprRealloc(ejs, backtrace, len + (int) strlen(traceLine) + 1); if (backtrace == 0) { return 0; } memcpy(&backtrace[len], traceLine, strlen(traceLine) + 1); len += (int) strlen(traceLine); mprFree(traceLine); } return backtrace; }
static EjsString *getBlockName(EjsMod *mp, EjsObj *block, int slotNum) { EjsName qname; if (block) { if (ejsIsType(mp->ejs, block)) { return ((EjsType*) block)->qname.name; } else if (ejsIsFunction(mp->ejs, block)) { return ((EjsFunction*) block)->name; } } qname = ejsGetPropertyName(mp->ejs, block, slotNum); return qname.name; }
/* Prepare form data as a series of key-value pairs. Data is formatted according to www-url-encoded specs by mprSetHttpFormData. Objects are flattened into a one level key/value pairs. Keys can have embedded "." separators. E.g. name=value&address=77%20Park%20Lane */ static void prepForm(Ejs *ejs, EjsHttp *hp, cchar *prefix, EjsObj *data) { EjsName qname; EjsObj *vp; EjsString *value; cchar *key, *sep, *vstr; char *encodedKey, *encodedValue, *newPrefix, *newKey; int i, count; count = ejsGetLength(ejs, data); for (i = 0; i < count; i++) { if (ejsIs(ejs, data, Array)) { key = itos(i); } else { qname = ejsGetPropertyName(ejs, data, i); key = ejsToMulti(ejs, qname.name); } vp = ejsGetProperty(ejs, data, i); if (vp == 0) { continue; } if (ejsGetLength(ejs, vp) > 0) { if (prefix) { newPrefix = sfmt("%s.%s", prefix, key); prepForm(ejs, hp, newPrefix, vp); } else { prepForm(ejs, hp, key, vp); } } else { value = ejsToString(ejs, vp); sep = (mprGetBufLength(hp->requestContent) > 0) ? "&" : ""; if (prefix) { newKey = sjoin(prefix, ".", key, NULL); encodedKey = mprUriEncode(newKey, MPR_ENCODE_URI_COMPONENT); } else { encodedKey = mprUriEncode(key, MPR_ENCODE_URI_COMPONENT); } vstr = ejsToMulti(ejs, value); encodedValue = mprUriEncode(vstr, MPR_ENCODE_URI_COMPONENT); mprPutToBuf(hp->requestContent, "%s%s=%s", sep, encodedKey, encodedValue); } } }
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; }
static EjsName getHostPropertyName(Ejs *ejs, EjsWebHost *rq, int slotNum) { return ejsGetPropertyName(ejs, (EjsVar*) rq->var.type->instanceBlock, slotNum); }
/* 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; }
/* * Format the stack backtrace */ char *ejsFormatStack(Ejs *ejs, EjsError *error) { EjsType *type; EjsFrame *fp; cchar *typeName, *functionName, *line, *typeSep, *codeSep; char *backtrace, *traceLine; int level, len, oldFlags; mprAssert(ejs); backtrace = 0; len = 0; level = 0; /* * Pretend to be the compiler so we can access function frame names */ oldFlags = ejs->flags; ejs->flags |= EJS_FLAG_COMPILER; for (fp = ejs->state->fp; fp; fp = fp->caller) { typeName = ""; functionName = "global"; if (fp->currentLine == 0) { line = ""; } else { for (line = fp->currentLine; *line && isspace((int) *line); line++) { ; } } if (fp) { if (fp->function.owner && fp->function.slotNum >= 0) { functionName = ejsGetPropertyName(ejs, fp->function.owner, fp->function.slotNum).name; } if (ejsIsType(fp->function.owner)) { type = (EjsType*) fp->function.owner; if (type) { typeName = type->qname.name; } } } typeSep = (*typeName) ? "." : ""; codeSep = (*line) ? "->" : ""; if (error && backtrace == 0) { error->filename = mprStrdup(error, fp->filename); error->lineNumber = fp->lineNumber; } if ((traceLine = mprAsprintf(ejs, MPR_MAX_STRING, " [%02d] %s, %s%s%s, line %d %s %s\n", level++, fp->filename ? fp->filename : "script", typeName, typeSep, functionName, fp->lineNumber, codeSep, line)) == NULL) { break; } backtrace = (char*) mprRealloc(ejs, backtrace, len + (int) strlen(traceLine) + 1); if (backtrace == 0) { return 0; } memcpy(&backtrace[len], traceLine, strlen(traceLine) + 1); len += (int) strlen(traceLine); mprFree(traceLine); } ejs->flags = oldFlags; if (error) { error->stack = backtrace; } return backtrace; }
/* 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); }
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"); }