mirror of
https://github.com/ccxvii/mujs.git
synced 2026-02-06 01:41:37 +08:00
The temporary array we use for sorting cannot be seen by the GC, and that violates the constraint that all js_Value values must always be reachable from the stack or global environment. Temporarily turning off the GC will let us use the temporary array for fast sorting using qsort(), without tripping over this violation.
747 lines
14 KiB
C
747 lines
14 KiB
C
#include "jsi.h"
|
|
#include "jsvalue.h"
|
|
#include "jsbuiltin.h"
|
|
|
|
int js_getlength(js_State *J, int idx)
|
|
{
|
|
int len;
|
|
js_getproperty(J, idx, "length");
|
|
len = js_tointeger(J, -1);
|
|
js_pop(J, 1);
|
|
return len;
|
|
}
|
|
|
|
void js_setlength(js_State *J, int idx, int len)
|
|
{
|
|
js_pushnumber(J, len);
|
|
js_setproperty(J, idx < 0 ? idx - 1 : idx, "length");
|
|
}
|
|
|
|
int js_hasindex(js_State *J, int idx, int i)
|
|
{
|
|
char buf[32];
|
|
return js_hasproperty(J, idx, js_itoa(buf, i));
|
|
}
|
|
|
|
void js_getindex(js_State *J, int idx, int i)
|
|
{
|
|
char buf[32];
|
|
js_getproperty(J, idx, js_itoa(buf, i));
|
|
}
|
|
|
|
void js_setindex(js_State *J, int idx, int i)
|
|
{
|
|
char buf[32];
|
|
js_setproperty(J, idx, js_itoa(buf, i));
|
|
}
|
|
|
|
void js_delindex(js_State *J, int idx, int i)
|
|
{
|
|
char buf[32];
|
|
js_delproperty(J, idx, js_itoa(buf, i));
|
|
}
|
|
|
|
static void jsB_new_Array(js_State *J)
|
|
{
|
|
int i, top = js_gettop(J);
|
|
|
|
js_newarray(J);
|
|
|
|
if (top == 2) {
|
|
if (js_isnumber(J, 1)) {
|
|
js_copy(J, 1);
|
|
js_setproperty(J, -2, "length");
|
|
} else {
|
|
js_copy(J, 1);
|
|
js_setindex(J, -2, 0);
|
|
}
|
|
} else {
|
|
for (i = 1; i < top; ++i) {
|
|
js_copy(J, i);
|
|
js_setindex(J, -2, i - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Ap_concat(js_State *J)
|
|
{
|
|
int i, top = js_gettop(J);
|
|
int n, k, len;
|
|
|
|
js_newarray(J);
|
|
n = 0;
|
|
|
|
for (i = 0; i < top; ++i) {
|
|
js_copy(J, i);
|
|
if (js_isarray(J, -1)) {
|
|
len = js_getlength(J, -1);
|
|
for (k = 0; k < len; ++k)
|
|
if (js_hasindex(J, -1, k))
|
|
js_setindex(J, -3, n++);
|
|
js_pop(J, 1);
|
|
} else {
|
|
js_setindex(J, -2, n++);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Ap_join(js_State *J)
|
|
{
|
|
char * volatile out = NULL;
|
|
const char *sep;
|
|
const char *r;
|
|
int seplen;
|
|
int k, n, len;
|
|
|
|
len = js_getlength(J, 0);
|
|
|
|
if (js_isdefined(J, 1)) {
|
|
sep = js_tostring(J, 1);
|
|
seplen = strlen(sep);
|
|
} else {
|
|
sep = ",";
|
|
seplen = 1;
|
|
}
|
|
|
|
if (len == 0) {
|
|
js_pushliteral(J, "");
|
|
return;
|
|
}
|
|
|
|
if (js_try(J)) {
|
|
js_free(J, out);
|
|
js_throw(J);
|
|
}
|
|
|
|
n = 1;
|
|
for (k = 0; k < len; ++k) {
|
|
js_getindex(J, 0, k);
|
|
if (js_isundefined(J, -1) || js_isnull(J, -1))
|
|
r = "";
|
|
else
|
|
r = js_tostring(J, -1);
|
|
n += strlen(r);
|
|
|
|
if (k == 0) {
|
|
out = js_malloc(J, n);
|
|
strcpy(out, r);
|
|
} else {
|
|
n += seplen;
|
|
out = js_realloc(J, out, n);
|
|
strcat(out, sep);
|
|
strcat(out, r);
|
|
}
|
|
|
|
js_pop(J, 1);
|
|
}
|
|
|
|
js_pushstring(J, out);
|
|
js_endtry(J);
|
|
js_free(J, out);
|
|
}
|
|
|
|
static void Ap_pop(js_State *J)
|
|
{
|
|
int n;
|
|
|
|
n = js_getlength(J, 0);
|
|
|
|
if (n > 0) {
|
|
js_getindex(J, 0, n - 1);
|
|
js_delindex(J, 0, n - 1);
|
|
js_setlength(J, 0, n - 1);
|
|
} else {
|
|
js_setlength(J, 0, 0);
|
|
js_pushundefined(J);
|
|
}
|
|
}
|
|
|
|
static void Ap_push(js_State *J)
|
|
{
|
|
int i, top = js_gettop(J);
|
|
int n;
|
|
|
|
n = js_getlength(J, 0);
|
|
|
|
for (i = 1; i < top; ++i, ++n) {
|
|
js_copy(J, i);
|
|
js_setindex(J, 0, n);
|
|
}
|
|
|
|
js_setlength(J, 0, n);
|
|
|
|
js_pushnumber(J, n);
|
|
}
|
|
|
|
static void Ap_reverse(js_State *J)
|
|
{
|
|
int len, middle, lower;
|
|
|
|
len = js_getlength(J, 0);
|
|
middle = len / 2;
|
|
lower = 0;
|
|
|
|
while (lower != middle) {
|
|
int upper = len - lower - 1;
|
|
int haslower = js_hasindex(J, 0, lower);
|
|
int hasupper = js_hasindex(J, 0, upper);
|
|
if (haslower && hasupper) {
|
|
js_setindex(J, 0, lower);
|
|
js_setindex(J, 0, upper);
|
|
} else if (hasupper) {
|
|
js_setindex(J, 0, lower);
|
|
js_delindex(J, 0, upper);
|
|
} else if (haslower) {
|
|
js_setindex(J, 0, upper);
|
|
js_delindex(J, 0, lower);
|
|
}
|
|
++lower;
|
|
}
|
|
|
|
js_copy(J, 0);
|
|
}
|
|
|
|
static void Ap_shift(js_State *J)
|
|
{
|
|
int k, len;
|
|
|
|
len = js_getlength(J, 0);
|
|
|
|
if (len == 0) {
|
|
js_setlength(J, 0, 0);
|
|
js_pushundefined(J);
|
|
return;
|
|
}
|
|
|
|
js_getindex(J, 0, 0);
|
|
|
|
for (k = 1; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k))
|
|
js_setindex(J, 0, k - 1);
|
|
else
|
|
js_delindex(J, 0, k - 1);
|
|
}
|
|
|
|
js_delindex(J, 0, len - 1);
|
|
js_setlength(J, 0, len - 1);
|
|
}
|
|
|
|
static void Ap_slice(js_State *J)
|
|
{
|
|
int len, s, e, n;
|
|
double sv, ev;
|
|
|
|
js_newarray(J);
|
|
|
|
len = js_getlength(J, 0);
|
|
sv = js_tointeger(J, 1);
|
|
ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len;
|
|
|
|
if (sv < 0) sv = sv + len;
|
|
if (ev < 0) ev = ev + len;
|
|
|
|
s = sv < 0 ? 0 : sv > len ? len : sv;
|
|
e = ev < 0 ? 0 : ev > len ? len : ev;
|
|
|
|
for (n = 0; s < e; ++s, ++n)
|
|
if (js_hasindex(J, 0, s))
|
|
js_setindex(J, -2, n);
|
|
}
|
|
|
|
struct sortslot {
|
|
js_Value v;
|
|
js_State *J;
|
|
};
|
|
|
|
static int sortcmp(const void *avoid, const void *bvoid)
|
|
{
|
|
const struct sortslot *aslot = avoid, *bslot = bvoid;
|
|
const js_Value *a = &aslot->v, *b = &bslot->v;
|
|
js_State *J = aslot->J;
|
|
const char *sx, *sy;
|
|
int c;
|
|
|
|
int unx = (a->type == JS_TUNDEFINED);
|
|
int uny = (b->type == JS_TUNDEFINED);
|
|
if (unx) return !uny;
|
|
if (uny) return -1;
|
|
|
|
if (js_iscallable(J, 1)) {
|
|
js_copy(J, 1); /* copy function */
|
|
js_pushundefined(J);
|
|
js_pushvalue(J, *a);
|
|
js_pushvalue(J, *b);
|
|
js_call(J, 2);
|
|
c = js_tonumber(J, -1);
|
|
js_pop(J, 1);
|
|
} else {
|
|
js_pushvalue(J, *a);
|
|
js_pushvalue(J, *b);
|
|
sx = js_tostring(J, -2);
|
|
sy = js_tostring(J, -1);
|
|
c = strcmp(sx, sy);
|
|
js_pop(J, 2);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
static void Ap_sort(js_State *J)
|
|
{
|
|
struct sortslot *array = NULL;
|
|
int i, n, len;
|
|
|
|
len = js_getlength(J, 0);
|
|
if (len <= 0) {
|
|
js_copy(J, 0);
|
|
return;
|
|
}
|
|
|
|
if (len >= INT_MAX / (int)sizeof(*array))
|
|
js_rangeerror(J, "array is too large to sort");
|
|
|
|
array = js_malloc(J, len * sizeof *array);
|
|
|
|
/* Holding objects where the GC cannot see them is illegal, but if we
|
|
* don't allow the GC to run we can use qsort() on a temporary array of
|
|
* js_Values for fast sorting.
|
|
*/
|
|
++J->gcpause;
|
|
|
|
if (js_try(J)) {
|
|
--J->gcpause;
|
|
js_free(J, array);
|
|
js_throw(J);
|
|
}
|
|
|
|
n = 0;
|
|
for (i = 0; i < len; ++i) {
|
|
if (js_hasindex(J, 0, i)) {
|
|
array[n].v = *js_tovalue(J, -1);
|
|
array[n].J = J;
|
|
js_pop(J, 1);
|
|
++n;
|
|
}
|
|
}
|
|
|
|
qsort(array, n, sizeof *array, sortcmp);
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
js_pushvalue(J, array[i].v);
|
|
js_setindex(J, 0, i);
|
|
}
|
|
for (i = n; i < len; ++i) {
|
|
js_delindex(J, 0, i);
|
|
}
|
|
|
|
--J->gcpause;
|
|
|
|
js_endtry(J);
|
|
js_free(J, array);
|
|
|
|
js_copy(J, 0);
|
|
}
|
|
|
|
static void Ap_splice(js_State *J)
|
|
{
|
|
int top = js_gettop(J);
|
|
int len, start, del, add, k;
|
|
double f;
|
|
|
|
js_newarray(J);
|
|
|
|
len = js_getlength(J, 0);
|
|
|
|
f = js_tointeger(J, 1);
|
|
if (f < 0) f = f + len;
|
|
start = f < 0 ? 0 : f > len ? len : f;
|
|
|
|
f = js_tointeger(J, 2);
|
|
del = f < 0 ? 0 : f > len - start ? len - start : f;
|
|
|
|
/* copy deleted items to return array */
|
|
for (k = 0; k < del; ++k)
|
|
if (js_hasindex(J, 0, start + k))
|
|
js_setindex(J, -2, k);
|
|
js_setlength(J, -1, del);
|
|
|
|
/* shift the tail to resize the hole left by deleted items */
|
|
add = top - 3;
|
|
if (add < del) {
|
|
for (k = start; k < len - del; ++k) {
|
|
if (js_hasindex(J, 0, k + del))
|
|
js_setindex(J, 0, k + add);
|
|
else
|
|
js_delindex(J, 0, k + add);
|
|
}
|
|
for (k = len; k > len - del + add; --k)
|
|
js_delindex(J, 0, k - 1);
|
|
} else if (add > del) {
|
|
for (k = len - del; k > start; --k) {
|
|
if (js_hasindex(J, 0, k + del - 1))
|
|
js_setindex(J, 0, k + add - 1);
|
|
else
|
|
js_delindex(J, 0, k + add - 1);
|
|
}
|
|
}
|
|
|
|
/* copy new items into the hole */
|
|
for (k = 0; k < add; ++k) {
|
|
js_copy(J, 3 + k);
|
|
js_setindex(J, 0, start + k);
|
|
}
|
|
|
|
js_setlength(J, 0, len - del + add);
|
|
}
|
|
|
|
static void Ap_unshift(js_State *J)
|
|
{
|
|
int i, top = js_gettop(J);
|
|
int k, len;
|
|
|
|
len = js_getlength(J, 0);
|
|
|
|
for (k = len; k > 0; --k) {
|
|
int from = k - 1;
|
|
int to = k + top - 2;
|
|
if (js_hasindex(J, 0, from))
|
|
js_setindex(J, 0, to);
|
|
else
|
|
js_delindex(J, 0, to);
|
|
}
|
|
|
|
for (i = 1; i < top; ++i) {
|
|
js_copy(J, i);
|
|
js_setindex(J, 0, i - 1);
|
|
}
|
|
|
|
js_setlength(J, 0, len + top - 1);
|
|
|
|
js_pushnumber(J, len + top - 1);
|
|
}
|
|
|
|
static void Ap_toString(js_State *J)
|
|
{
|
|
int top = js_gettop(J);
|
|
js_pop(J, top - 1);
|
|
Ap_join(J);
|
|
}
|
|
|
|
static void Ap_indexOf(js_State *J)
|
|
{
|
|
int k, len, from;
|
|
|
|
len = js_getlength(J, 0);
|
|
from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0;
|
|
if (from < 0) from = len + from;
|
|
if (from < 0) from = 0;
|
|
|
|
js_copy(J, 1);
|
|
for (k = from; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
if (js_strictequal(J)) {
|
|
js_pushnumber(J, k);
|
|
return;
|
|
}
|
|
js_pop(J, 1);
|
|
}
|
|
}
|
|
|
|
js_pushnumber(J, -1);
|
|
}
|
|
|
|
static void Ap_lastIndexOf(js_State *J)
|
|
{
|
|
int k, len, from;
|
|
|
|
len = js_getlength(J, 0);
|
|
from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1;
|
|
if (from > len - 1) from = len - 1;
|
|
if (from < 0) from = len + from;
|
|
|
|
js_copy(J, 1);
|
|
for (k = from; k >= 0; --k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
if (js_strictequal(J)) {
|
|
js_pushnumber(J, k);
|
|
return;
|
|
}
|
|
js_pop(J, 1);
|
|
}
|
|
}
|
|
|
|
js_pushnumber(J, -1);
|
|
}
|
|
|
|
static void Ap_every(js_State *J)
|
|
{
|
|
int hasthis = js_gettop(J) >= 3;
|
|
int k, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
len = js_getlength(J, 0);
|
|
for (k = 0; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
if (hasthis)
|
|
js_copy(J, 2);
|
|
else
|
|
js_pushundefined(J);
|
|
js_copy(J, -3);
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 3);
|
|
if (!js_toboolean(J, -1))
|
|
return;
|
|
js_pop(J, 2);
|
|
}
|
|
}
|
|
|
|
js_pushboolean(J, 1);
|
|
}
|
|
|
|
static void Ap_some(js_State *J)
|
|
{
|
|
int hasthis = js_gettop(J) >= 3;
|
|
int k, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
len = js_getlength(J, 0);
|
|
for (k = 0; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
if (hasthis)
|
|
js_copy(J, 2);
|
|
else
|
|
js_pushundefined(J);
|
|
js_copy(J, -3);
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 3);
|
|
if (js_toboolean(J, -1))
|
|
return;
|
|
js_pop(J, 2);
|
|
}
|
|
}
|
|
|
|
js_pushboolean(J, 0);
|
|
}
|
|
|
|
static void Ap_forEach(js_State *J)
|
|
{
|
|
int hasthis = js_gettop(J) >= 3;
|
|
int k, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
len = js_getlength(J, 0);
|
|
for (k = 0; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
if (hasthis)
|
|
js_copy(J, 2);
|
|
else
|
|
js_pushundefined(J);
|
|
js_copy(J, -3);
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 3);
|
|
js_pop(J, 2);
|
|
}
|
|
}
|
|
|
|
js_pushundefined(J);
|
|
}
|
|
|
|
static void Ap_map(js_State *J)
|
|
{
|
|
int hasthis = js_gettop(J) >= 3;
|
|
int k, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
js_newarray(J);
|
|
|
|
len = js_getlength(J, 0);
|
|
for (k = 0; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
if (hasthis)
|
|
js_copy(J, 2);
|
|
else
|
|
js_pushundefined(J);
|
|
js_copy(J, -3);
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 3);
|
|
js_setindex(J, -3, k);
|
|
js_pop(J, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Ap_filter(js_State *J)
|
|
{
|
|
int hasthis = js_gettop(J) >= 3;
|
|
int k, to, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
js_newarray(J);
|
|
to = 0;
|
|
|
|
len = js_getlength(J, 0);
|
|
for (k = 0; k < len; ++k) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
if (hasthis)
|
|
js_copy(J, 2);
|
|
else
|
|
js_pushundefined(J);
|
|
js_copy(J, -3);
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 3);
|
|
if (js_toboolean(J, -1)) {
|
|
js_pop(J, 1);
|
|
js_setindex(J, -2, to++);
|
|
} else {
|
|
js_pop(J, 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void Ap_reduce(js_State *J)
|
|
{
|
|
int hasinitial = js_gettop(J) >= 3;
|
|
int k, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
len = js_getlength(J, 0);
|
|
k = 0;
|
|
|
|
if (len == 0 && !hasinitial)
|
|
js_typeerror(J, "no initial value");
|
|
|
|
/* initial value of accumulator */
|
|
if (hasinitial)
|
|
js_copy(J, 2);
|
|
else {
|
|
while (k < len)
|
|
if (js_hasindex(J, 0, k++))
|
|
break;
|
|
if (k == len)
|
|
js_typeerror(J, "no initial value");
|
|
}
|
|
|
|
while (k < len) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
js_pushundefined(J);
|
|
js_rot(J, 4); /* accumulator on top */
|
|
js_rot(J, 4); /* property on top */
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 4); /* calculate new accumulator */
|
|
}
|
|
++k;
|
|
}
|
|
|
|
/* return accumulator */
|
|
}
|
|
|
|
static void Ap_reduceRight(js_State *J)
|
|
{
|
|
int hasinitial = js_gettop(J) >= 3;
|
|
int k, len;
|
|
|
|
if (!js_iscallable(J, 1))
|
|
js_typeerror(J, "callback is not a function");
|
|
|
|
len = js_getlength(J, 0);
|
|
k = len - 1;
|
|
|
|
if (len == 0 && !hasinitial)
|
|
js_typeerror(J, "no initial value");
|
|
|
|
/* initial value of accumulator */
|
|
if (hasinitial)
|
|
js_copy(J, 2);
|
|
else {
|
|
while (k >= 0)
|
|
if (js_hasindex(J, 0, k--))
|
|
break;
|
|
if (k < 0)
|
|
js_typeerror(J, "no initial value");
|
|
}
|
|
|
|
while (k >= 0) {
|
|
if (js_hasindex(J, 0, k)) {
|
|
js_copy(J, 1);
|
|
js_pushundefined(J);
|
|
js_rot(J, 4); /* accumulator on top */
|
|
js_rot(J, 4); /* property on top */
|
|
js_pushnumber(J, k);
|
|
js_copy(J, 0);
|
|
js_call(J, 4); /* calculate new accumulator */
|
|
}
|
|
--k;
|
|
}
|
|
|
|
/* return accumulator */
|
|
}
|
|
|
|
static void A_isArray(js_State *J)
|
|
{
|
|
if (js_isobject(J, 1)) {
|
|
js_Object *T = js_toobject(J, 1);
|
|
js_pushboolean(J, T->type == JS_CARRAY);
|
|
} else {
|
|
js_pushboolean(J, 0);
|
|
}
|
|
}
|
|
|
|
void jsB_initarray(js_State *J)
|
|
{
|
|
js_pushobject(J, J->Array_prototype);
|
|
{
|
|
jsB_propf(J, "Array.prototype.toString", Ap_toString, 0);
|
|
jsB_propf(J, "Array.prototype.concat", Ap_concat, 0); /* 1 */
|
|
jsB_propf(J, "Array.prototype.join", Ap_join, 1);
|
|
jsB_propf(J, "Array.prototype.pop", Ap_pop, 0);
|
|
jsB_propf(J, "Array.prototype.push", Ap_push, 0); /* 1 */
|
|
jsB_propf(J, "Array.prototype.reverse", Ap_reverse, 0);
|
|
jsB_propf(J, "Array.prototype.shift", Ap_shift, 0);
|
|
jsB_propf(J, "Array.prototype.slice", Ap_slice, 2);
|
|
jsB_propf(J, "Array.prototype.sort", Ap_sort, 1);
|
|
jsB_propf(J, "Array.prototype.splice", Ap_splice, 0); /* 2 */
|
|
jsB_propf(J, "Array.prototype.unshift", Ap_unshift, 0); /* 1 */
|
|
|
|
/* ES5 */
|
|
jsB_propf(J, "Array.prototype.indexOf", Ap_indexOf, 1);
|
|
jsB_propf(J, "Array.prototype.lastIndexOf", Ap_lastIndexOf, 1);
|
|
jsB_propf(J, "Array.prototype.every", Ap_every, 1);
|
|
jsB_propf(J, "Array.prototype.some", Ap_some, 1);
|
|
jsB_propf(J, "Array.prototype.forEach", Ap_forEach, 1);
|
|
jsB_propf(J, "Array.prototype.map", Ap_map, 1);
|
|
jsB_propf(J, "Array.prototype.filter", Ap_filter, 1);
|
|
jsB_propf(J, "Array.prototype.reduce", Ap_reduce, 1);
|
|
jsB_propf(J, "Array.prototype.reduceRight", Ap_reduceRight, 1);
|
|
}
|
|
js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 0); /* 1 */
|
|
{
|
|
/* ES5 */
|
|
jsB_propf(J, "Array.isArray", A_isArray, 1);
|
|
}
|
|
js_defglobal(J, "Array", JS_DONTENUM);
|
|
}
|