/** * Iterate over all elements in the object and find all elements for which the matching function is true. * The match is called with the following signature: * * function match(arrayElement: Object, elementIndex: Number, arr: Array): Boolean * * @param match Matching function * @return Returns a new array containing all matching elements. */ static EjsVar *findAll(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsVar *funArgs[3]; EjsBoolean *result; EjsArray *elements; int i; mprAssert(argc == 1 && ejsIsFunction(argv[0])); elements = ejsCreateArray(ejs, 0); if (elements == 0) { ejsThrowMemoryError(ejs); return 0; } for (i = 0; i < ap->length; i++) { funArgs[0] = ap->obj.properties.slots[i]; /* Array element */ funArgs[1] = (EjsVar*) ejsCreateNumber(ejs, i); /* element index */ funArgs[2] = (EjsVar*) ap; /* Array */ result = (EjsBoolean*) ejsRunFunction(ejs, (EjsFunction*) argv[0], 0, 3, funArgs); if (result == 0 || !ejsIsBoolean(result) || !result->value) { setArrayProperty(ejs, elements, elements->length, ap->obj.properties.slots[i]); } } return (EjsVar*) elements; }
/* * Return an array of table names in the database. * function get tables(): Array */ static EjsVar *tables(Ejs *ejs, EjsDb *db, int argc, EjsVar **argv) { EjsArray *ap; char **data, *error; int rc, rowCount, i; ejsSetDbMemoryContext(db->tls, db->arena); ap = ejsCreateArray(ejs, 0); rc = sqlite3_get_table(db->sdb, "SELECT name FROM sqlite_master " "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'" "UNION ALL " "SELECT name FROM sqlite_temp_master " "WHERE type IN ('table','view') " "ORDER BY 1", &data, &rowCount, 0, &error); if (error) { ejsThrowIOError(ejs, "%s", error); sqlite3_free(error); } if (rc == SQLITE_OK){ for (i = 1; i <= rowCount; i++) { ejsSetProperty(ejs, (EjsVar*) ap, i - 1, (EjsVar*) ejsCreateString(ejs, data[i])); } } sqlite3_free_table(data); return (EjsVar*) ap; }
static EjsVar *makeIntersection(Ejs *ejs, EjsArray *lhs, EjsArray *rhs) { EjsArray *result; EjsVar **l, **r, **resultSlots; int i, j, k; result = ejsCreateArray(ejs, 0); l = lhs->data; r = rhs->data; for (i = 0; i < lhs->length; i++) { for (j = 0; j < rhs->length; j++) { if (compareArrayElement(ejs, l[i], r[j])) { resultSlots = result->data; for (k = 0; k < result->length; k++) { if (compareArrayElement(ejs, l[i], resultSlots[k])) { break; } } if (result->length == 0 || k == result->length) { setArrayProperty(ejs, result, -1, l[i]); } } } } return (EjsVar*) result; }
EjsArray *ejsCaptureStack(Ejs *ejs, int uplevels) { EjsFrame *fp; EjsState *state; EjsArray *stack; wchar *source; EjsObj *frame; char *filename; int index, lineNumber; assert(ejs); stack = ejsCreateArray(ejs, 0); index = 0; for (state = ejs->state; state; state = state->prev) { for (fp = state->fp; fp; fp = fp->caller) { if (uplevels-- <= 0) { frame = ejsCreateEmptyPot(ejs); if (ejsGetDebugInfo(ejs, (EjsFunction*) fp, fp->pc, &filename, &lineNumber, &source) >= 0) { ejsSetPropertyByName(ejs, frame, EN("filename"), ejsCreatePathFromAsc(ejs, filename)); ejsSetPropertyByName(ejs, frame, EN("lineno"), ejsCreateNumber(ejs, lineNumber)); ejsSetPropertyByName(ejs, frame, EN("code"), ejsCreateString(ejs, source, wlen(source))); } else { ejsSetPropertyByName(ejs, frame, EN("filename"), EST(undefined)); } ejsSetPropertyByName(ejs, frame, EN("func"), fp->function.name); ejsSetProperty(ejs, stack, index++, frame); } } } return stack; }
/* Get the application command line arguments static function get args(): Array */ static EjsArray *app_args(Ejs *ejs, EjsObj *unused, int argc, EjsObj **argv) { EjsArray *args; int i; args = ejsCreateArray(ejs, ejs->argc); for (i = 0; i < ejs->argc; i++) { ejsSetProperty(ejs, args, i, ejsCreateStringFromAsc(ejs, ejs->argv[i])); } return args; }
/* * Get the application command line arguments * * static function get args(): String */ static EjsVar *getArgs(Ejs *ejs, EjsObject *unused, int argc, EjsVar **argv) { EjsArray *args; int i; args = ejsCreateArray(ejs, ejs->argc); for (i = 0; i < ejs->argc; i++) { ejsSetProperty(ejs, (EjsVar*) args, i, (EjsVar*) ejsCreateString(ejs, ejs->argv[i])); } return (EjsVar*) args; }
/* * A header object from a given hash table */ static EjsVar *createHeaderObject(Ejs *ejs, MprHashTable *table) { MprHash *hp; EjsVar *headers, *header; EjsName qname; int index; headers = (EjsVar*) ejsCreateArray(ejs, mprGetHashCount(table)); for (index = 0, hp = 0; (hp = mprGetNextHash(table, hp)) != 0; ) { header = (EjsVar*) ejsCreateSimpleObject(ejs); ejsSetPropertyByName(ejs, header, ejsName(&qname, "", hp->key), (EjsVar*) ejsCreateString(ejs, hp->data)); ejsSetProperty(ejs, headers, index++, header); } return headers; }
/* * Concatenate the supplied elements with the array to create a new array. If any arguments specify an array, * their elements are catenated. This is a one level deep copy. * * function concat(...args): Array */ static EjsVar *concatArray(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsArray *args, *newArray, *vpa; EjsVar *vp, **src, **dest; int i, k, next; mprAssert(argc == 1 && ejsIsArray(argv[0])); args = ((EjsArray*) argv[0]); newArray = ejsCreateArray(ejs, ap->length); src = ap->data; dest = newArray->data; /* * Copy the original array */ for (next = 0; next < ap->length; next++) { dest[next] = src[next]; } /* * Copy the args. If any element is itself an array, then flatten it and copy its elements. */ for (i = 0; i < args->length; i++) { vp = args->data[i]; if (ejsIsArray(vp)) { vpa = (EjsArray*) vp; if (growArray(ejs, newArray, next + vpa->length) < 0) { ejsThrowMemoryError(ejs); return 0; } dest = newArray->data; dest = newArray->data; for (k = 0; k < vpa->length; k++) { dest[next++] = vpa->data[k]; } } else { if (growArray(ejs, newArray, next + 1) < 0) { ejsThrowMemoryError(ejs); return 0; } dest[next++] = vp; } } return (EjsVar*) newArray; }
static EjsArray *makeUnion(Ejs *ejs, EjsArray *lhs, EjsArray *rhs) { EjsArray *result; EjsObj **l, **r; int i; result = ejsCreateArray(ejs, 0); l = lhs->data; r = rhs->data; for (i = 0; i < lhs->length; i++) { addUnique(ejs, result, l[i]); } for (i = 0; i < rhs->length; i++) { addUnique(ejs, result, r[i]); } return result; }
/* function get providers(): Array */ static EjsArray *http_providers(Ejs *ejs, EjsHttp *hp, int argc, EjsObj **argv) { EjsArray *result; int i; result = ejsCreateArray(ejs, 0); i = 0; #if BIT_PACK_EST ejsSetProperty(ejs, result, i++, ejsCreateStringFromAsc(ejs, "est")); #endif #if BIT_PACK_OPENSSL ejsSetProperty(ejs, result, i++, ejsCreateStringFromAsc(ejs, "openssl")); #endif #if BIT_PACK_MATRIXSSL ejsSetProperty(ejs, result, i++, ejsCreateStringFromAsc(ejs, "matrixssl")); #endif #if BIT_PACK_MOCANA ejsSetProperty(ejs, result, i++, ejsCreateStringFromAsc(ejs, "mocana")); #endif return result; }
/* function exec(str: String, start: Number = 0): Array */ static EjsArray *regex_exec(Ejs *ejs, EjsRegExp *rp, int argc, EjsObj **argv) { EjsArray *results; EjsString *match, *str; int matches[BIT_MAX_REGEX_MATCHES * 3]; int count, start, len, i, index; str = (EjsString*) argv[0]; if (argc == 2) { start = (int) ejsGetNumber(ejs, argv[1]); } else { start = rp->endLastMatch; } rp->matched = 0; assert(rp->compiled); count = pcre_exec(rp->compiled, NULL, str->value, (int) str->length, start, 0, matches, sizeof(matches) / sizeof(int)); if (count < 0) { rp->endLastMatch = 0; return ESV(null); } results = ejsCreateArray(ejs, count); for (index = 0, i = 0; i < count; i++, index += 2) { len = matches[index + 1] - matches[index]; match = ejsCreateString(ejs, &str->value[matches[index]], len); ejsSetProperty(ejs, results, i, match); if (index == 0) { rp->matched = match; } } if (rp->global) { /* Only save if global flag used as per spec */ rp->startLastMatch = matches[0]; rp->endLastMatch = matches[1]; } return results; }
/* * function sql(cmd: String): Array * * Will support multiple sql cmds but will only return one result table. */ static EjsVar *sql(Ejs *ejs, EjsDb *db, int argc, EjsVar **argv) { sqlite3 *sdb; sqlite3_stmt *stmt; EjsArray *result; EjsVar *row, *svalue; EjsName qname; cchar *tail, *colName, *cmd, *value; int i, ncol, rc, retries, rowNum; mprAssert(ejs); mprAssert(db); cmd = ejsGetString(argv[0]); ejsSetDbMemoryContext(db->tls, db->arena); rc = SQLITE_OK; retries = 0; sdb = db->sdb; if (sdb == 0) { ejsThrowIOError(ejs, "Database is closed"); return 0; } mprAssert(sdb); result = ejsCreateArray(ejs, 0); if (result == 0) { return 0; } while (cmd && *cmd && (rc == SQLITE_OK || (rc == SQLITE_SCHEMA && ++retries < 2))) { stmt = 0; rc = sqlite3_prepare_v2(sdb, cmd, -1, &stmt, &tail); if (rc != SQLITE_OK) { continue; } if (stmt == 0) { /* Comment or white space */ cmd = tail; continue; } ncol = sqlite3_column_count(stmt); for (rowNum = 0; ; rowNum++) { rc = sqlite3_step(stmt); if (rc == SQLITE_ROW) { row = (EjsVar*) ejsCreateSimpleObject(ejs); if (row == 0) { sqlite3_finalize(stmt); return 0; } if (ejsSetProperty(ejs, (EjsVar*) result, rowNum, row) < 0) { /* TODO rc */ } for (i = 0; i < ncol; i++) { colName = sqlite3_column_name(stmt, i); value = (cchar*) sqlite3_column_text(stmt, i); ejsName(&qname, EJS_EMPTY_NAMESPACE, mprStrdup(row, colName)); if (ejsLookupProperty(ejs, row, &qname) < 0) { svalue = (EjsVar*) ejsCreateString(ejs, mprStrdup(row, value)); if (ejsSetPropertyByName(ejs, row, &qname, svalue) < 0) { /* TODO */ } } } } else { rc = sqlite3_finalize(stmt); stmt = 0; if (rc != SQLITE_SCHEMA) { // TODO - what is this? retries = 0; for (cmd = tail; isspace(*cmd); cmd++) { ; } } break; } #if UNUSED /* TODO -- should we be doing this */ cmd = tail; #endif } } if (stmt) { rc = sqlite3_finalize(stmt); } if (rc != SQLITE_OK) { if (rc == sqlite3_errcode(sdb)) { ejsThrowIOError(ejs, "SQL error: %s", sqlite3_errmsg(sdb)); } else { ejsThrowIOError(ejs, "Unspecified SQL error"); } return 0; } return (EjsVar*) result; }
/* return a empty mpr array */ struct MprVar mprArray(const char *name) { return ejsCreateArray(name && *name?name:"(NULL)", 0); }
/* Parse an object literal string pointed to by js->next into the given buffer. Update js->next to point to the next input token in the object literal. Supports nested object literals. */ static EjsObj *parseLiteralInner(Ejs *ejs, MprBuf *buf, JsonState *js) { EjsAny *obj, *vp; MprBuf *valueBuf; wchar *token, *key, *value; int tid, isArray; isArray = 0; tid = getNextJsonToken(buf, &token, js); if (tid == TOK_ERR || tid == TOK_EOF) { return 0; } if (tid == TOK_LBRACKET) { isArray = 1; obj = (EjsObj*) ejsCreateArray(ejs, 0); } else if (tid == TOK_LBRACE) { obj = ejsCreateEmptyPot(ejs); } else { return ejsParse(ejs, token, S_String); } if (obj == 0) { ejsThrowMemoryError(ejs); return 0; } while (1) { vp = 0; tid = peekNextJsonToken(js); if (tid == TOK_ERR) { return 0; } else if (tid == TOK_EOF) { break; } else if (tid == TOK_RBRACE || tid == TOK_RBRACKET) { getNextJsonToken(buf, &key, js); break; } if (tid == TOK_LBRACKET) { /* For array values */ vp = parseLiteral(ejs, js); assert(vp); } else if (tid == TOK_LBRACE) { /* For object values */ vp = parseLiteral(ejs, js); assert(vp); } else if (isArray) { tid = getNextJsonToken(buf, &value, js); vp = ejsParse(ejs, value, (tid == TOK_QID) ? S_String: -1); assert(vp); } else { getNextJsonToken(buf, &key, js); tid = peekNextJsonToken(js); if (tid == TOK_ERR) { return 0; } else if (tid == TOK_EOF) { break; } else if (tid == TOK_LBRACE || tid == TOK_LBRACKET) { vp = parseLiteral(ejs, js); } else if (tid == TOK_ID || tid == TOK_QID) { valueBuf = mprCreateBuf(0, 0); getNextJsonToken(valueBuf, &value, js); if (tid == TOK_QID) { vp = ejsCreateString(ejs, value, strlen(value)); } else { if (mcmp(value, "null") == 0) { vp = ESV(null); } else if (mcmp(value, "undefined") == 0) { vp = ESV(undefined); } else { vp = ejsParse(ejs, value, -1); } } assert(vp); } else { getNextJsonToken(buf, &value, js); js->error = js->next; return 0; } } if (vp == 0) { js->error = js->next; return 0; } if (isArray) { if (ejsSetProperty(ejs, obj, -1, vp) < 0) { ejsThrowMemoryError(ejs); return 0; } } else { if (ejsSetPropertyByName(ejs, obj, WEN(key), vp) < 0) { ejsThrowMemoryError(ejs); return 0; } } } return obj; }
MprVar espCreateArrayVar(char *name, int size) { return ejsCreateArray(name, size); }
/* * Create a new array by taking a slice from an array. * * function slice(start: Number, end: Number, step: Number = 1): Array */ static EjsVar *sliceArray(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsArray *result; EjsVar **src, **dest; int start, end, step, i, j, len, size; mprAssert(1 <= argc && argc <= 3); start = ejsGetInt(argv[0]); if (argc >= 2) { end = ejsGetInt(argv[1]); } else { end = ap->length; } if (argc == 3) { step = ejsGetInt(argv[2]); } else { step = 1; } if (step == 0) { step = 1; } if (start < 0) { start += ap->length; } if (start < 0) { start = 0; } else if (start >= ap->length) { start = ap->length; } if (end < 0) { end += ap->length; } if (end < 0) { end = 0; } else if (end >= ap->length) { end = ap->length; } size = (start < end) ? end - start : start - end; /* * This may allocate too many elements if abs(step) is > 1, but length will still be correct. */ result = ejsCreateArray(ejs, size); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } src = ap->data; dest = result->data; len = 0; if (step > 0) { for (i = start, j = 0; i < end; i += step, j++) { dest[j] = src[i]; len++; } } else { for (i = start, j = 0; i > end; i += step, j++) { dest[j] = src[i]; len++; } } result->length = len; return (EjsVar*) result; }
static EjsAny *invokeArrayOperator(Ejs *ejs, EjsAny *lhs, int opcode, EjsAny *rhs) { EjsAny *result; if (rhs == 0 || TYPE(lhs) != TYPE(rhs)) { if ((result = coerceArrayOperands(ejs, lhs, opcode, rhs)) != 0) { return result; } } switch (opcode) { case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_GE: return ejsCreateBoolean(ejs, (lhs == rhs)); case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GT: return ejsCreateBoolean(ejs, !(lhs == rhs)); /* Unary operators */ case EJS_OP_COMPARE_NOT_ZERO: return ESV(true); case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NULL: case EJS_OP_COMPARE_FALSE: case EJS_OP_COMPARE_TRUE: case EJS_OP_COMPARE_ZERO: return ESV(false); case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return ESV(one); /* Binary operators */ case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_REM: case EJS_OP_SHR: case EJS_OP_USHR: case EJS_OP_XOR: return ESV(zero); /* Operator overload */ case EJS_OP_ADD: result = ejsCreateArray(ejs, 0); pushArray(ejs, result, 1, &lhs); pushArray(ejs, result, 1, &rhs); return result; case EJS_OP_AND: return makeIntersection(ejs, lhs, rhs); case EJS_OP_OR: return makeUnion(ejs, lhs, rhs); case EJS_OP_SHL: return pushArray(ejs, lhs, 1, &rhs); case EJS_OP_SUB: return ejsRemoveItems(ejs, lhs, rhs); default: ejsThrowTypeError(ejs, "Opcode %d not implemented for type %@", opcode, TYPE(lhs)->qname.name); return 0; } assert(0); }
/* * Insert, remove or replace array elements. Return the removed elements. * * function splice(start: Number, deleteCount: Number, ...values): Array * */ static EjsVar *spliceArray(Ejs *ejs, EjsArray *ap, int argc, EjsVar **argv) { EjsArray *result, *values; EjsVar **data, **dest, **items; int start, deleteCount, i, delta, endInsert, oldLen; mprAssert(1 <= argc && argc <= 3); start = ejsGetInt(argv[0]); deleteCount = ejsGetInt(argv[1]); values = (EjsArray*) argv[2]; if (ap->length == 0) { if (deleteCount <= 0) { return (EjsVar*) ap; } ejsThrowArgError(ejs, "Array is empty"); return 0; } if (start < 0) { start += ap->length; } if (start < 0) { start = 0; } if (start >= ap->length) { start = ap->length - 1; } if (deleteCount < 0) { deleteCount = ap->length - start + 1; } if (deleteCount > ap->length) { deleteCount = ap->length; } result = ejsCreateArray(ejs, deleteCount); if (result == 0) { ejsThrowMemoryError(ejs); return 0; } data = ap->data; dest = result->data; items = values->data; /* * Copy removed items to the result */ for (i = 0; i < deleteCount; i++) { dest[i] = data[i + start]; } oldLen = ap->length; delta = values->length - deleteCount; if (delta > 0) { /* * Make room for items to insert */ if (growArray(ejs, ap, ap->length + delta) < 0) { return 0; } data = ap->data; endInsert = start + delta; for (i = ap->length - 1; i >= endInsert; i--) { data[i] = data[i - delta]; } } else { ap->length += delta; } /* * Copy in new values */ for (i = 0; i < values->length; i++) { data[start + i] = items[i]; } /* * Remove holes */ if (delta < 0) { for (i = start + values->length; i < oldLen; i++) { data[i] = data[i - delta]; } } return (EjsVar*) result; }
static EjsVar *invokeArrayOperator(Ejs *ejs, EjsVar *lhs, int opcode, EjsVar *rhs) { EjsVar *result; if (rhs == 0 || lhs->type != rhs->type) { if ((result = coerceArrayOperands(ejs, lhs, opcode, rhs)) != 0) { return result; } } switch (opcode) { case EJS_OP_COMPARE_EQ: case EJS_OP_COMPARE_STRICTLY_EQ: case EJS_OP_COMPARE_LE: case EJS_OP_COMPARE_GE: return (EjsVar*) ejsCreateBoolean(ejs, (lhs == rhs)); case EJS_OP_COMPARE_NE: case EJS_OP_COMPARE_STRICTLY_NE: case EJS_OP_COMPARE_LT: case EJS_OP_COMPARE_GT: return (EjsVar*) ejsCreateBoolean(ejs, !(lhs == rhs)); /* * Unary operators */ case EJS_OP_COMPARE_NOT_ZERO: return (EjsVar*) ejs->trueValue; case EJS_OP_COMPARE_UNDEFINED: case EJS_OP_COMPARE_NULL: case EJS_OP_COMPARE_FALSE: case EJS_OP_COMPARE_TRUE: case EJS_OP_COMPARE_ZERO: return (EjsVar*) ejs->falseValue; case EJS_OP_LOGICAL_NOT: case EJS_OP_NOT: case EJS_OP_NEG: return (EjsVar*) ejs->oneValue; /* * Binary operators */ case EJS_OP_DIV: case EJS_OP_MUL: case EJS_OP_REM: case EJS_OP_SHR: case EJS_OP_USHR: case EJS_OP_XOR: return (EjsVar*) ejs->zeroValue; #if BLD_FEATURE_EJS_LANG >= EJS_SPEC_PLUS /* * Operator overload */ case EJS_OP_ADD: result = (EjsVar*) ejsCreateArray(ejs, 0); pushArray(ejs, (EjsArray*) result, 1, (EjsVar**) &lhs); pushArray(ejs, (EjsArray*) result, 1, (EjsVar**) &rhs); return result; case EJS_OP_AND: return (EjsVar*) makeIntersection(ejs, (EjsArray*) lhs, (EjsArray*) rhs); case EJS_OP_OR: return (EjsVar*) makeUnion(ejs, (EjsArray*) lhs, (EjsArray*) rhs); case EJS_OP_SHL: return pushArray(ejs, (EjsArray*) lhs, 1, &rhs); case EJS_OP_SUB: return (EjsVar*) removeArrayElements(ejs, (EjsArray*) lhs, (EjsArray*) rhs); #endif default: ejsThrowTypeError(ejs, "Opcode %d not implemented for type %s", opcode, lhs->type->qname.name); return 0; } mprAssert(0); }