зеркало из https://github.com/mozilla/gecko-dev.git
Bug 290592: Add |forEach|, |indexOf|, |filter|, |map|, |some| and |every| to
Array.prototype, for greater Lispy righteousness. r+a=brendan.
This commit is contained in:
Родитель
89f668af1b
Коммит
fea422d9f2
223
js/src/jsarray.c
223
js/src/jsarray.c
|
@ -48,6 +48,7 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsbool.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsconfig.h"
|
||||
#include "jsfun.h"
|
||||
|
@ -1351,6 +1352,219 @@ array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
}
|
||||
#endif /* JS_HAS_SEQUENCE_OPS */
|
||||
|
||||
#if JS_HAS_ARRAY_EXTRAS
|
||||
static JSBool
|
||||
array_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
jsuint len, i;
|
||||
|
||||
if (!js_GetLengthProperty(cx, obj, &len))
|
||||
return JS_FALSE;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
jsid id;
|
||||
jsval v;
|
||||
|
||||
if (!IndexToId(cx, i, &id) ||
|
||||
!OBJ_GET_PROPERTY(cx, obj, id, &v)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (js_StrictlyEqual(v, argv[0])) {
|
||||
*rval = INT_TO_JSVAL(i);
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*rval = INT_TO_JSVAL(-1);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Order is important; extras that use a caller's predicate must follow MAP. */
|
||||
typedef enum ArrayExtraMode {
|
||||
FOREACH,
|
||||
MAP,
|
||||
FILTER,
|
||||
SOME,
|
||||
EVERY
|
||||
} ArrayExtraMode;
|
||||
|
||||
static JSBool
|
||||
array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval,
|
||||
ArrayExtraMode mode)
|
||||
{
|
||||
jsuint len, newlen, i;
|
||||
JSObject *funobj, *thisp, *newarr;
|
||||
jsval *sp, *origsp, *oldsp;
|
||||
void *mark;
|
||||
JSStackFrame *fp;
|
||||
JSBool ok, b;
|
||||
|
||||
if (!js_GetLengthProperty(cx, obj, &len))
|
||||
return JS_FALSE;
|
||||
|
||||
if (len == 0 || argc == 0)
|
||||
return JS_TRUE;
|
||||
|
||||
if (JSVAL_IS_FUNCTION(cx, argv[0])) {
|
||||
funobj = JSVAL_TO_OBJECT(argv[0]);
|
||||
} else {
|
||||
JSFunction *fun = js_ValueToFunction(cx, &argv[0], 0);
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
funobj = fun->object;
|
||||
argv[0] = OBJECT_TO_JSVAL(funobj);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
if (!js_ValueToObject(cx, argv[1], &thisp))
|
||||
return JS_FALSE;
|
||||
argv[1] = OBJECT_TO_JSVAL(thisp);
|
||||
} else {
|
||||
JSObject *tmp;
|
||||
thisp = funobj;
|
||||
while ((tmp = OBJ_GET_PARENT(cx, thisp)) != NULL)
|
||||
thisp = tmp;
|
||||
}
|
||||
|
||||
if (mode == MAP || mode == FILTER) {
|
||||
newlen = (mode == MAP ? len : 0);
|
||||
newarr = js_NewArrayObject(cx, newlen, NULL);
|
||||
if (!newarr)
|
||||
return JS_FALSE;
|
||||
*rval = OBJECT_TO_JSVAL(newarr);
|
||||
}
|
||||
|
||||
/* We call with 2 args, value and index, plus room for rval. */
|
||||
origsp = js_AllocStack(cx, 2 + 3, &mark);
|
||||
if (!origsp)
|
||||
return JS_FALSE;
|
||||
|
||||
/* Lift current frame to include our args. */
|
||||
fp = cx->fp;
|
||||
oldsp = fp->sp;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
jsid id;
|
||||
jsval v, rval2;
|
||||
|
||||
ok = IndexToId(cx, i, &id);
|
||||
if (!ok)
|
||||
break;
|
||||
ok = OBJ_GET_PROPERTY(cx, obj, id, &v);
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
/* Push funobj and 'this', then args. */
|
||||
sp = origsp;
|
||||
*sp++ = OBJECT_TO_JSVAL(funobj);
|
||||
*sp++ = OBJECT_TO_JSVAL(thisp);
|
||||
*sp++ = v;
|
||||
*sp++ = INT_TO_JSVAL(i);
|
||||
|
||||
/* Do the call. */
|
||||
fp->sp = sp;
|
||||
ok = js_Invoke(cx, 2, JSINVOKE_INTERNAL);
|
||||
rval2 = fp->sp[-1];
|
||||
fp->sp = oldsp;
|
||||
if (!ok)
|
||||
break;
|
||||
|
||||
if (mode > MAP) {
|
||||
if (rval2 == JSVAL_NULL) {
|
||||
b = JS_FALSE;
|
||||
} else if (JSVAL_IS_BOOLEAN(rval2)) {
|
||||
b = JSVAL_TO_BOOLEAN(rval2);
|
||||
} else {
|
||||
ok = js_ValueToBoolean(cx, rval2, &b);
|
||||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case FOREACH:
|
||||
break;
|
||||
case MAP:
|
||||
ok = OBJ_SET_PROPERTY(cx, newarr, id, &rval2);
|
||||
if (!ok)
|
||||
goto out;
|
||||
break;
|
||||
case FILTER:
|
||||
if (!b)
|
||||
break;
|
||||
/* Filter passed v, push as result. */
|
||||
ok = IndexToId(cx, newlen++, &id);
|
||||
if (!ok)
|
||||
goto out;
|
||||
ok = OBJ_SET_PROPERTY(cx, newarr, id, &v);
|
||||
if (!ok)
|
||||
goto out;
|
||||
break;
|
||||
case SOME:
|
||||
if (b) {
|
||||
*rval = JSVAL_TRUE;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case EVERY:
|
||||
if (!b) {
|
||||
*rval = JSVAL_FALSE;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mode == SOME)
|
||||
*rval = JSVAL_FALSE;
|
||||
else if (mode == EVERY)
|
||||
*rval = JSVAL_TRUE;
|
||||
out:
|
||||
js_FreeStack(cx, mark);
|
||||
if (ok && mode == FILTER)
|
||||
ok = js_SetLengthProperty(cx, newarr, newlen);
|
||||
return ok;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_forEach(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
return array_extra(cx, obj, argc, argv, rval, FOREACH);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_map(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
return array_extra(cx, obj, argc, argv, rval, MAP);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_filter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
return array_extra(cx, obj, argc, argv, rval, FILTER);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_some(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
return array_extra(cx, obj, argc, argv, rval, SOME);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_every(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval)
|
||||
{
|
||||
return array_extra(cx, obj, argc, argv, rval, EVERY);
|
||||
}
|
||||
#endif
|
||||
|
||||
static JSFunctionSpec array_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
{js_toSource_str, array_toSource, 0,0,0},
|
||||
|
@ -1378,6 +1592,15 @@ static JSFunctionSpec array_methods[] = {
|
|||
{"slice", array_slice, 2,0,0},
|
||||
#endif
|
||||
|
||||
#if JS_HAS_ARRAY_EXTRAS
|
||||
{"indexOf", array_indexOf, 1,0,0},
|
||||
{"forEach", array_forEach, 1,0,0},
|
||||
{"map", array_map, 1,0,0},
|
||||
{"filter", array_filter, 1,0,0},
|
||||
{"some", array_some, 1,0,0},
|
||||
{"every", array_every, 1,0,0},
|
||||
#endif
|
||||
|
||||
{0,0,0,0,0}
|
||||
};
|
||||
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */
|
||||
|
||||
#elif JS_VERSION == 100
|
||||
|
||||
|
@ -193,6 +194,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */
|
||||
|
||||
#elif JS_VERSION == 110
|
||||
|
||||
|
@ -252,6 +254,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */
|
||||
|
||||
#elif JS_VERSION == 120
|
||||
|
||||
|
@ -311,6 +314,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */
|
||||
|
||||
#elif JS_VERSION == 130
|
||||
|
||||
|
@ -370,6 +374,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */
|
||||
|
||||
#elif JS_VERSION == 140
|
||||
|
||||
|
@ -429,6 +434,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 0 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 0 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 0 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 0 /* has indexOf and Lispy extras */
|
||||
|
||||
#elif JS_VERSION == 150
|
||||
|
||||
|
@ -488,6 +494,7 @@
|
|||
#define JS_HAS_LVALUE_RETURN 1 /* has o.item(i) = j; for native item */
|
||||
#define JS_HAS_NO_SUCH_METHOD 1 /* has o.__noSuchMethod__ handler */
|
||||
#define JS_HAS_XML_SUPPORT 1 /* has ECMAScript for XML support */
|
||||
#define JS_HAS_ARRAY_EXTRAS 1 /* has indexOf and Lispy extras */
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -1755,6 +1755,38 @@ bad:
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_StrictlyEqual(jsval lval, jsval rval)
|
||||
{
|
||||
jsval ltag = JSVAL_TAG(lval), rtag = JSVAL_TAG(rval);
|
||||
jsdouble ld, rd;
|
||||
|
||||
if (ltag == rtag) {
|
||||
if (ltag == JSVAL_STRING) {
|
||||
JSString *lstr = JSVAL_TO_STRING(lval),
|
||||
*rstr = JSVAL_TO_STRING(rval);
|
||||
return js_CompareStrings(lstr, rstr) == 0;
|
||||
}
|
||||
if (ltag == JSVAL_DOUBLE) {
|
||||
ld = *JSVAL_TO_DOUBLE(lval);
|
||||
rd = *JSVAL_TO_DOUBLE(rval);
|
||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||
}
|
||||
return lval == rval;
|
||||
}
|
||||
if (ltag == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) {
|
||||
ld = *JSVAL_TO_DOUBLE(lval);
|
||||
rd = JSVAL_TO_INT(rval);
|
||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||
}
|
||||
if (JSVAL_IS_INT(lval) && rtag == JSVAL_DOUBLE) {
|
||||
ld = JSVAL_TO_INT(lval);
|
||||
rd = *JSVAL_TO_DOUBLE(rval);
|
||||
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
|
||||
}
|
||||
return lval == rval;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
InternStringElementId(JSContext *cx, jsval idval, jsid *idp)
|
||||
{
|
||||
|
@ -2851,52 +2883,26 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
|||
break;
|
||||
|
||||
#if !JS_BUG_FALLIBLE_EQOPS
|
||||
#define NEW_EQUALITY_OP(OP, IFNAN) \
|
||||
#define NEW_EQUALITY_OP(OP) \
|
||||
JS_BEGIN_MACRO \
|
||||
rval = FETCH_OPND(-1); \
|
||||
lval = FETCH_OPND(-2); \
|
||||
ltmp = JSVAL_TAG(lval); \
|
||||
rtmp = JSVAL_TAG(rval); \
|
||||
if (ltmp == rtmp) { \
|
||||
if (ltmp == JSVAL_STRING) { \
|
||||
str = JSVAL_TO_STRING(lval); \
|
||||
str2 = JSVAL_TO_STRING(rval); \
|
||||
cond = js_CompareStrings(str, str2) OP 0; \
|
||||
} else if (ltmp == JSVAL_DOUBLE) { \
|
||||
d = *JSVAL_TO_DOUBLE(lval); \
|
||||
d2 = *JSVAL_TO_DOUBLE(rval); \
|
||||
cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
|
||||
} else { \
|
||||
cond = lval OP rval; \
|
||||
} \
|
||||
} else { \
|
||||
if (ltmp == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { \
|
||||
d = *JSVAL_TO_DOUBLE(lval); \
|
||||
d2 = JSVAL_TO_INT(rval); \
|
||||
cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
|
||||
} else if (JSVAL_IS_INT(lval) && rtmp == JSVAL_DOUBLE) { \
|
||||
d = JSVAL_TO_INT(lval); \
|
||||
d2 = *JSVAL_TO_DOUBLE(rval); \
|
||||
cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \
|
||||
} else { \
|
||||
cond = lval OP rval; \
|
||||
} \
|
||||
} \
|
||||
cond = js_StrictlyEqual(lval, rval) OP JS_TRUE; \
|
||||
sp--; \
|
||||
STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
|
||||
JS_END_MACRO
|
||||
|
||||
case JSOP_NEW_EQ:
|
||||
NEW_EQUALITY_OP(==, JS_FALSE);
|
||||
NEW_EQUALITY_OP(==);
|
||||
break;
|
||||
|
||||
case JSOP_NEW_NE:
|
||||
NEW_EQUALITY_OP(!=, JS_TRUE);
|
||||
NEW_EQUALITY_OP(!=);
|
||||
break;
|
||||
|
||||
#if JS_HAS_SWITCH_STATEMENT
|
||||
case JSOP_CASE:
|
||||
NEW_EQUALITY_OP(==, JS_FALSE);
|
||||
NEW_EQUALITY_OP(==);
|
||||
(void) POP();
|
||||
if (cond) {
|
||||
len = GET_JUMP_OFFSET(pc);
|
||||
|
@ -2907,7 +2913,7 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
|||
break;
|
||||
|
||||
case JSOP_CASEX:
|
||||
NEW_EQUALITY_OP(==, JS_FALSE);
|
||||
NEW_EQUALITY_OP(==);
|
||||
(void) POP();
|
||||
if (cond) {
|
||||
len = GET_JUMPX_OFFSET(pc);
|
||||
|
|
|
@ -296,6 +296,9 @@ extern JSBool
|
|||
js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
|
||||
JSObject **objp, JSProperty **propp);
|
||||
|
||||
extern JSBool
|
||||
js_StrictlyEqual(jsval lval, jsval rval);
|
||||
|
||||
extern JSBool
|
||||
js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче