| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751 |
- #include "jsi.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");
- }
- 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 * volatile r = NULL;
- const char *sep;
- int seplen;
- int k, n, len, rlen;
- 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 = 0;
- for (k = 0; k < len; ++k) {
- js_getindex(J, 0, k);
- if (js_iscoercible(J, -1)) {
- r = js_tostring(J, -1);
- rlen = strlen(r);
- } else {
- rlen = 0;
- }
- if (k == 0) {
- out = js_malloc(J, rlen + 1);
- if (rlen > 0) {
- memcpy(out, r, rlen);
- n += rlen;
- }
- } else {
- if (n + seplen + rlen > JS_STRLIMIT)
- js_rangeerror(J, "invalid string length");
- out = js_realloc(J, out, n + seplen + rlen + 1);
- if (seplen > 0) {
- memcpy(out + n, sep, seplen);
- n += seplen;
- }
- if (rlen > 0) {
- memcpy(out + n, r, rlen);
- n += rlen;
- }
- }
- js_pop(J, 1);
- }
- js_pushlstring(J, out, n);
- 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;
- double v;
- int c;
- int unx = (a->t.type == JS_TUNDEFINED);
- int uny = (b->t.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);
- v = js_tonumber(J, -1);
- c = (v == 0) ? 0 : (v < 0) ? -1 : 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 * volatile 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");
- /* 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);
- }
- array = js_malloc(J, len * sizeof *array);
- 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 = len-i; i >= n; --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;
- len = js_getlength(J, 0);
- start = js_tointeger(J, 1);
- if (start < 0)
- start = (len + start) > 0 ? len + start : 0;
- else if (start > len)
- start = len;
- if (js_isdefined(J, 2))
- del = js_tointeger(J, 2);
- else
- del = len - start;
- if (del > len - start)
- del = len - start;
- if (del < 0)
- del = 0;
- js_newarray(J);
- /* 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)
- {
- if (!js_iscoercible(J, 0))
- js_typeerror(J, "'this' is not an object");
- js_getproperty(J, 0, "join");
- if (!js_iscallable(J, -1)) {
- js_pop(J, 1);
- // TODO: call Object.prototype.toString implementation directly
- js_getglobal(J, "Object");
- js_getproperty(J, -1, "prototype");
- js_rot2pop1(J);
- js_getproperty(J, -1, "toString");
- js_rot2pop1(J);
- }
- js_copy(J, 0);
- js_call(J, 0);
- }
- 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);
- }
- }
- js_setlength(J, -1, len);
- }
- 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, 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);
- }
|