/src/mupdf/thirdparty/mujs/jsarray.c
Line | Count | Source |
1 | | #include "jsi.h" |
2 | | |
3 | | #ifndef JS_HEAPSORT |
4 | | #define JS_HEAPSORT 0 |
5 | | #endif |
6 | | |
7 | | int js_getlength(js_State *J, int idx) |
8 | 0 | { |
9 | 0 | int len; |
10 | 0 | js_getproperty(J, idx, "length"); |
11 | 0 | len = js_tointeger(J, -1); |
12 | 0 | js_pop(J, 1); |
13 | 0 | return len; |
14 | 0 | } |
15 | | |
16 | | void js_setlength(js_State *J, int idx, int len) |
17 | 0 | { |
18 | 0 | js_pushnumber(J, len); |
19 | 0 | js_setproperty(J, idx < 0 ? idx - 1 : idx, "length"); |
20 | 0 | } |
21 | | |
22 | | static void jsB_new_Array(js_State *J) |
23 | 0 | { |
24 | 0 | int i, top = js_gettop(J); |
25 | |
|
26 | 0 | js_newarray(J); |
27 | |
|
28 | 0 | if (top == 2) { |
29 | 0 | if (js_isnumber(J, 1)) { |
30 | 0 | js_copy(J, 1); |
31 | 0 | js_setproperty(J, -2, "length"); |
32 | 0 | } else { |
33 | 0 | js_copy(J, 1); |
34 | 0 | js_setindex(J, -2, 0); |
35 | 0 | } |
36 | 0 | } else { |
37 | 0 | for (i = 1; i < top; ++i) { |
38 | 0 | js_copy(J, i); |
39 | 0 | js_setindex(J, -2, i - 1); |
40 | 0 | } |
41 | 0 | } |
42 | 0 | } |
43 | | |
44 | | static void Ap_concat(js_State *J) |
45 | 0 | { |
46 | 0 | int i, top = js_gettop(J); |
47 | 0 | int n, k, len; |
48 | |
|
49 | 0 | js_newarray(J); |
50 | 0 | n = 0; |
51 | |
|
52 | 0 | for (i = 0; i < top; ++i) { |
53 | 0 | js_copy(J, i); |
54 | 0 | if (js_isarray(J, -1)) { |
55 | 0 | len = js_getlength(J, -1); |
56 | 0 | for (k = 0; k < len; ++k) |
57 | 0 | if (js_hasindex(J, -1, k)) |
58 | 0 | js_setindex(J, -3, n++); |
59 | 0 | js_pop(J, 1); |
60 | 0 | } else { |
61 | 0 | js_setindex(J, -2, n++); |
62 | 0 | } |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | | /* ugly cycle detection for Array.prototype.join */ |
67 | | static void Ap_join(js_State *J); |
68 | | static void Ap_toString(js_State *J); |
69 | | static int Ap_join_cycle(js_State *J) |
70 | 0 | { |
71 | 0 | js_Object *needle = js_toobject(J, 0); |
72 | 0 | int top = J->tracetop - 1; |
73 | 0 | while (top > 0) { |
74 | 0 | int stk = J->trace[top].stack; |
75 | 0 | js_Value *fun = &J->stack[stk-1]; |
76 | 0 | if (fun->t.type != JS_TOBJECT) return 0; |
77 | 0 | if (fun->u.object->type != JS_CCFUNCTION) return 0; |
78 | 0 | if (fun->u.object->u.c.function == Ap_join) |
79 | 0 | { |
80 | 0 | js_Value *obj = &J->stack[stk]; |
81 | 0 | if (obj->t.type != JS_TOBJECT) return 0; |
82 | 0 | if (obj->u.object == needle) |
83 | 0 | return 1; |
84 | 0 | } |
85 | 0 | else if (fun->u.object->u.c.function == Ap_toString) |
86 | 0 | { |
87 | | /* join calls toString which calls join which calls toString, etc */ |
88 | 0 | } |
89 | 0 | else |
90 | 0 | { |
91 | 0 | return 0; |
92 | 0 | } |
93 | 0 | --top; |
94 | 0 | } |
95 | 0 | return 0; |
96 | 0 | } |
97 | | |
98 | | static void Ap_join(js_State *J) |
99 | 0 | { |
100 | 0 | char * volatile out = NULL; |
101 | 0 | const char * volatile r = NULL; |
102 | 0 | const char *sep; |
103 | 0 | int seplen; |
104 | 0 | int k, n, len, rlen; |
105 | |
|
106 | 0 | if (Ap_join_cycle(J)) { |
107 | 0 | js_pushliteral(J, ""); |
108 | 0 | return; |
109 | 0 | } |
110 | | |
111 | 0 | len = js_getlength(J, 0); |
112 | |
|
113 | 0 | if (js_isdefined(J, 1)) { |
114 | 0 | sep = js_tostring(J, 1); |
115 | 0 | seplen = strlen(sep); |
116 | 0 | } else { |
117 | 0 | sep = ","; |
118 | 0 | seplen = 1; |
119 | 0 | } |
120 | |
|
121 | 0 | if (len <= 0) { |
122 | 0 | js_pushliteral(J, ""); |
123 | 0 | return; |
124 | 0 | } |
125 | | |
126 | 0 | if (js_try(J)) { |
127 | 0 | js_free(J, out); |
128 | 0 | js_throw(J); |
129 | 0 | } |
130 | | |
131 | 0 | n = 0; |
132 | 0 | for (k = 0; k < len; ++k) { |
133 | 0 | js_getindex(J, 0, k); |
134 | 0 | if (js_iscoercible(J, -1)) { |
135 | 0 | r = js_tostring(J, -1); |
136 | 0 | rlen = strlen(r); |
137 | 0 | } else { |
138 | 0 | rlen = 0; |
139 | 0 | } |
140 | |
|
141 | 0 | if (k == 0) { |
142 | 0 | out = js_malloc(J, rlen + 1); |
143 | 0 | if (rlen > 0) { |
144 | 0 | memcpy(out, r, rlen); |
145 | 0 | n += rlen; |
146 | 0 | } |
147 | 0 | } else { |
148 | 0 | if (n + seplen + rlen > JS_STRLIMIT) |
149 | 0 | js_rangeerror(J, "invalid string length"); |
150 | 0 | out = js_realloc(J, out, n + seplen + rlen + 1); |
151 | 0 | if (seplen > 0) { |
152 | 0 | memcpy(out + n, sep, seplen); |
153 | 0 | n += seplen; |
154 | 0 | } |
155 | 0 | if (rlen > 0) { |
156 | 0 | memcpy(out + n, r, rlen); |
157 | 0 | n += rlen; |
158 | 0 | } |
159 | 0 | } |
160 | | |
161 | 0 | js_pop(J, 1); |
162 | 0 | } |
163 | | |
164 | 0 | js_pushlstring(J, out, n); |
165 | 0 | js_endtry(J); |
166 | 0 | js_free(J, out); |
167 | 0 | } |
168 | | |
169 | | static void Ap_pop(js_State *J) |
170 | 0 | { |
171 | 0 | int n; |
172 | |
|
173 | 0 | n = js_getlength(J, 0); |
174 | |
|
175 | 0 | if (n > 0) { |
176 | 0 | js_getindex(J, 0, n - 1); |
177 | 0 | js_delindex(J, 0, n - 1); |
178 | 0 | js_setlength(J, 0, n - 1); |
179 | 0 | } else { |
180 | 0 | js_setlength(J, 0, 0); |
181 | 0 | js_pushundefined(J); |
182 | 0 | } |
183 | 0 | } |
184 | | |
185 | | static void Ap_push(js_State *J) |
186 | 0 | { |
187 | 0 | int i, top = js_gettop(J); |
188 | 0 | int n; |
189 | |
|
190 | 0 | n = js_getlength(J, 0); |
191 | |
|
192 | 0 | for (i = 1; i < top; ++i, ++n) { |
193 | 0 | js_copy(J, i); |
194 | 0 | js_setindex(J, 0, n); |
195 | 0 | } |
196 | |
|
197 | 0 | js_setlength(J, 0, n); |
198 | |
|
199 | 0 | js_pushnumber(J, n); |
200 | 0 | } |
201 | | |
202 | | static void Ap_reverse(js_State *J) |
203 | 0 | { |
204 | 0 | int len, middle, lower; |
205 | |
|
206 | 0 | len = js_getlength(J, 0); |
207 | 0 | middle = len / 2; |
208 | 0 | lower = 0; |
209 | |
|
210 | 0 | while (lower != middle) { |
211 | 0 | int upper = len - lower - 1; |
212 | 0 | int haslower = js_hasindex(J, 0, lower); |
213 | 0 | int hasupper = js_hasindex(J, 0, upper); |
214 | 0 | if (haslower && hasupper) { |
215 | 0 | js_setindex(J, 0, lower); |
216 | 0 | js_setindex(J, 0, upper); |
217 | 0 | } else if (hasupper) { |
218 | 0 | js_setindex(J, 0, lower); |
219 | 0 | js_delindex(J, 0, upper); |
220 | 0 | } else if (haslower) { |
221 | 0 | js_setindex(J, 0, upper); |
222 | 0 | js_delindex(J, 0, lower); |
223 | 0 | } |
224 | 0 | ++lower; |
225 | 0 | } |
226 | |
|
227 | 0 | js_copy(J, 0); |
228 | 0 | } |
229 | | |
230 | | static void Ap_shift(js_State *J) |
231 | 0 | { |
232 | 0 | int k, len; |
233 | |
|
234 | 0 | len = js_getlength(J, 0); |
235 | |
|
236 | 0 | if (len == 0) { |
237 | 0 | js_setlength(J, 0, 0); |
238 | 0 | js_pushundefined(J); |
239 | 0 | return; |
240 | 0 | } |
241 | | |
242 | 0 | js_getindex(J, 0, 0); |
243 | |
|
244 | 0 | for (k = 1; k < len; ++k) { |
245 | 0 | if (js_hasindex(J, 0, k)) |
246 | 0 | js_setindex(J, 0, k - 1); |
247 | 0 | else |
248 | 0 | js_delindex(J, 0, k - 1); |
249 | 0 | } |
250 | |
|
251 | 0 | js_delindex(J, 0, len - 1); |
252 | 0 | js_setlength(J, 0, len - 1); |
253 | 0 | } |
254 | | |
255 | | static void Ap_slice(js_State *J) |
256 | 0 | { |
257 | 0 | int len, s, e, n; |
258 | 0 | double sv, ev; |
259 | |
|
260 | 0 | js_newarray(J); |
261 | |
|
262 | 0 | len = js_getlength(J, 0); |
263 | 0 | sv = js_tointeger(J, 1); |
264 | 0 | ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len; |
265 | |
|
266 | 0 | if (sv < 0) sv = sv + len; |
267 | 0 | if (ev < 0) ev = ev + len; |
268 | |
|
269 | 0 | s = sv < 0 ? 0 : sv > len ? len : sv; |
270 | 0 | e = ev < 0 ? 0 : ev > len ? len : ev; |
271 | |
|
272 | 0 | for (n = 0; s < e; ++s, ++n) |
273 | 0 | if (js_hasindex(J, 0, s)) |
274 | 0 | js_setindex(J, -2, n); |
275 | 0 | } |
276 | | |
277 | | static int Ap_sort_cmp(js_State *J, int idx_a, int idx_b) |
278 | 0 | { |
279 | 0 | js_Object *obj = js_tovalue(J, 0)->u.object; |
280 | 0 | if (obj->u.a.simple && idx_b < obj->u.a.flat_length) { |
281 | 0 | js_Value *val_a = &obj->u.a.array[idx_a]; |
282 | 0 | js_Value *val_b = &obj->u.a.array[idx_b]; |
283 | 0 | int und_a = val_a->t.type == JS_TUNDEFINED; |
284 | 0 | int und_b = val_b->t.type == JS_TUNDEFINED; |
285 | 0 | if (und_a) return und_b; |
286 | 0 | if (und_b) return -1; |
287 | 0 | if (js_iscallable(J, 1)) { |
288 | 0 | double v; |
289 | 0 | js_copy(J, 1); /* copy function */ |
290 | 0 | js_pushundefined(J); /* no 'this' binding */ |
291 | 0 | js_pushvalue(J, *val_a); |
292 | 0 | js_pushvalue(J, *val_b); |
293 | 0 | js_call(J, 2); |
294 | 0 | v = js_tonumber(J, -1); |
295 | 0 | js_pop(J, 1); |
296 | 0 | if (isnan(v)) |
297 | 0 | return 0; |
298 | 0 | if (v == 0) |
299 | 0 | return 0; |
300 | 0 | return v < 0 ? -1 : 1; |
301 | 0 | } else { |
302 | 0 | const char *str_a, *str_b; |
303 | 0 | int c; |
304 | 0 | js_pushvalue(J, *val_a); |
305 | 0 | js_pushvalue(J, *val_b); |
306 | 0 | str_a = js_tostring(J, -2); |
307 | 0 | str_b = js_tostring(J, -1); |
308 | 0 | c = strcmp(str_a, str_b); |
309 | 0 | js_pop(J, 2); |
310 | 0 | return c; |
311 | 0 | } |
312 | 0 | } else { |
313 | 0 | int und_a, und_b; |
314 | 0 | int has_a = js_hasindex(J, 0, idx_a); |
315 | 0 | int has_b = js_hasindex(J, 0, idx_b); |
316 | 0 | if (!has_a && !has_b) { |
317 | 0 | return 0; |
318 | 0 | } |
319 | 0 | if (has_a && !has_b) { |
320 | 0 | js_pop(J, 1); |
321 | 0 | return -1; |
322 | 0 | } |
323 | 0 | if (!has_a && has_b) { |
324 | 0 | js_pop(J, 1); |
325 | 0 | return 1; |
326 | 0 | } |
327 | | |
328 | 0 | und_a = js_isundefined(J, -2); |
329 | 0 | und_b = js_isundefined(J, -1); |
330 | 0 | if (und_a) { |
331 | 0 | js_pop(J, 2); |
332 | 0 | return und_b; |
333 | 0 | } |
334 | 0 | if (und_b) { |
335 | 0 | js_pop(J, 2); |
336 | 0 | return -1; |
337 | 0 | } |
338 | | |
339 | 0 | if (js_iscallable(J, 1)) { |
340 | 0 | double v; |
341 | 0 | js_copy(J, 1); /* copy function */ |
342 | 0 | js_pushundefined(J); /* no 'this' binding */ |
343 | 0 | js_copy(J, -4); |
344 | 0 | js_copy(J, -4); |
345 | 0 | js_call(J, 2); |
346 | 0 | v = js_tonumber(J, -1); |
347 | 0 | js_pop(J, 3); |
348 | 0 | if (isnan(v)) |
349 | 0 | return 0; |
350 | 0 | if (v == 0) |
351 | 0 | return 0; |
352 | 0 | return v < 0 ? -1 : 1; |
353 | 0 | } else { |
354 | 0 | const char *str_a = js_tostring(J, -2); |
355 | 0 | const char *str_b = js_tostring(J, -1); |
356 | 0 | int c = strcmp(str_a, str_b); |
357 | 0 | js_pop(J, 2); |
358 | 0 | return c; |
359 | 0 | } |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | | static void Ap_sort_swap(js_State *J, int idx_a, int idx_b) |
364 | 0 | { |
365 | 0 | js_Object *obj = js_tovalue(J, 0)->u.object; |
366 | 0 | if (obj->u.a.simple && idx_b < obj->u.a.flat_length) { |
367 | 0 | js_Value tmp = obj->u.a.array[idx_a]; |
368 | 0 | obj->u.a.array[idx_a] = obj->u.a.array[idx_b]; |
369 | 0 | obj->u.a.array[idx_b] = tmp; |
370 | 0 | } else { |
371 | 0 | int has_a = js_hasindex(J, 0, idx_a); |
372 | 0 | int has_b = js_hasindex(J, 0, idx_b); |
373 | 0 | if (has_a && has_b) { |
374 | 0 | js_setindex(J, 0, idx_a); |
375 | 0 | js_setindex(J, 0, idx_b); |
376 | 0 | } else if (has_a && !has_b) { |
377 | 0 | js_delindex(J, 0, idx_a); |
378 | 0 | js_setindex(J, 0, idx_b); |
379 | 0 | } else if (!has_a && has_b) { |
380 | 0 | js_delindex(J, 0, idx_b); |
381 | 0 | js_setindex(J, 0, idx_a); |
382 | 0 | } |
383 | 0 | } |
384 | 0 | } |
385 | | |
386 | | /* A bottom-up/bouncing heapsort implementation */ |
387 | | |
388 | | static int Ap_sort_leaf(js_State *J, int i, int end) |
389 | 0 | { |
390 | 0 | int j = i; |
391 | 0 | int lc = (j << 1) + 1; /* left child */ |
392 | 0 | int rc = (j << 1) + 2; /* right child */ |
393 | 0 | while (rc < end) { |
394 | 0 | if (Ap_sort_cmp(J, lc, rc) <= 0) |
395 | 0 | j = rc; |
396 | 0 | else |
397 | 0 | j = lc; |
398 | 0 | lc = (j << 1) + 1; |
399 | 0 | rc = (j << 1) + 2; |
400 | 0 | } |
401 | 0 | if (lc < end) |
402 | 0 | j = lc; |
403 | 0 | return j; |
404 | 0 | } |
405 | | |
406 | | static void Ap_sort_sift(js_State *J, int i, int end) |
407 | 0 | { |
408 | 0 | int j = Ap_sort_leaf(J, i, end); |
409 | 0 | while (j > i && Ap_sort_cmp(J, i, j) > 0) { |
410 | 0 | j = (j - 1) >> 1; /* parent */ |
411 | 0 | } |
412 | 0 | while (j > i) { |
413 | 0 | Ap_sort_swap(J, i, j); |
414 | 0 | j = (j - 1) >> 1; /* parent */ |
415 | 0 | } |
416 | 0 | } |
417 | | |
418 | | static void Ap_sort_heapsort(js_State *J, int n) |
419 | 0 | { |
420 | 0 | int i; |
421 | 0 | for (i = n / 2 - 1; i >= 0; --i) |
422 | 0 | Ap_sort_sift(J, i, n); |
423 | 0 | for (i = n - 1; i > 0; --i) { |
424 | 0 | Ap_sort_swap(J, 0, i); |
425 | 0 | Ap_sort_sift(J, 0, i); |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | | static void Ap_sort(js_State *J) |
430 | 0 | { |
431 | 0 | int len; |
432 | |
|
433 | 0 | len = js_getlength(J, 0); |
434 | 0 | if (len <= 1) { |
435 | 0 | js_copy(J, 0); |
436 | 0 | return; |
437 | 0 | } |
438 | | |
439 | 0 | if (!js_iscallable(J, 1) && !js_isundefined(J, 1)) |
440 | 0 | js_typeerror(J, "comparison function must be a function or undefined"); |
441 | | |
442 | 0 | if (len >= INT_MAX) |
443 | 0 | js_rangeerror(J, "array is too large to sort"); |
444 | | |
445 | 0 | Ap_sort_heapsort(J, len); |
446 | |
|
447 | 0 | js_copy(J, 0); |
448 | 0 | } |
449 | | |
450 | | static void Ap_splice(js_State *J) |
451 | 0 | { |
452 | 0 | int top = js_gettop(J); |
453 | 0 | int len, start, del, add, k; |
454 | |
|
455 | 0 | len = js_getlength(J, 0); |
456 | 0 | start = js_tointeger(J, 1); |
457 | 0 | if (start < 0) |
458 | 0 | start = (len + start) > 0 ? len + start : 0; |
459 | 0 | else if (start > len) |
460 | 0 | start = len; |
461 | |
|
462 | 0 | if (js_isdefined(J, 2)) |
463 | 0 | del = js_tointeger(J, 2); |
464 | 0 | else |
465 | 0 | del = len - start; |
466 | 0 | if (del > len - start) |
467 | 0 | del = len - start; |
468 | 0 | if (del < 0) |
469 | 0 | del = 0; |
470 | |
|
471 | 0 | js_newarray(J); |
472 | | |
473 | | /* copy deleted items to return array */ |
474 | 0 | for (k = 0; k < del; ++k) |
475 | 0 | if (js_hasindex(J, 0, start + k)) |
476 | 0 | js_setindex(J, -2, k); |
477 | 0 | js_setlength(J, -1, del); |
478 | | |
479 | | /* shift the tail to resize the hole left by deleted items */ |
480 | 0 | add = top - 3; |
481 | 0 | if (add < del) { |
482 | 0 | for (k = start; k < len - del; ++k) { |
483 | 0 | if (js_hasindex(J, 0, k + del)) |
484 | 0 | js_setindex(J, 0, k + add); |
485 | 0 | else |
486 | 0 | js_delindex(J, 0, k + add); |
487 | 0 | } |
488 | 0 | for (k = len; k > len - del + add; --k) |
489 | 0 | js_delindex(J, 0, k - 1); |
490 | 0 | } else if (add > del) { |
491 | 0 | for (k = len - del; k > start; --k) { |
492 | 0 | if (js_hasindex(J, 0, k + del - 1)) |
493 | 0 | js_setindex(J, 0, k + add - 1); |
494 | 0 | else |
495 | 0 | js_delindex(J, 0, k + add - 1); |
496 | 0 | } |
497 | 0 | } |
498 | | |
499 | | /* copy new items into the hole */ |
500 | 0 | for (k = 0; k < add; ++k) { |
501 | 0 | js_copy(J, 3 + k); |
502 | 0 | js_setindex(J, 0, start + k); |
503 | 0 | } |
504 | |
|
505 | 0 | js_setlength(J, 0, len - del + add); |
506 | 0 | } |
507 | | |
508 | | static void Ap_unshift(js_State *J) |
509 | 0 | { |
510 | 0 | int i, top = js_gettop(J); |
511 | 0 | int k, len; |
512 | |
|
513 | 0 | len = js_getlength(J, 0); |
514 | |
|
515 | 0 | for (k = len; k > 0; --k) { |
516 | 0 | int from = k - 1; |
517 | 0 | int to = k + top - 2; |
518 | 0 | if (js_hasindex(J, 0, from)) |
519 | 0 | js_setindex(J, 0, to); |
520 | 0 | else |
521 | 0 | js_delindex(J, 0, to); |
522 | 0 | } |
523 | |
|
524 | 0 | for (i = 1; i < top; ++i) { |
525 | 0 | js_copy(J, i); |
526 | 0 | js_setindex(J, 0, i - 1); |
527 | 0 | } |
528 | |
|
529 | 0 | js_setlength(J, 0, len + top - 1); |
530 | |
|
531 | 0 | js_pushnumber(J, len + top - 1); |
532 | 0 | } |
533 | | |
534 | | static void Ap_toString(js_State *J) |
535 | 0 | { |
536 | 0 | if (!js_iscoercible(J, 0)) |
537 | 0 | js_typeerror(J, "'this' is not an object"); |
538 | 0 | js_getproperty(J, 0, "join"); |
539 | 0 | if (!js_iscallable(J, -1)) { |
540 | 0 | js_pop(J, 1); |
541 | | /* TODO: call Object.prototype.toString implementation directly */ |
542 | 0 | js_getglobal(J, "Object"); |
543 | 0 | js_getproperty(J, -1, "prototype"); |
544 | 0 | js_rot2pop1(J); |
545 | 0 | js_getproperty(J, -1, "toString"); |
546 | 0 | js_rot2pop1(J); |
547 | 0 | } |
548 | 0 | js_copy(J, 0); |
549 | 0 | js_call(J, 0); |
550 | 0 | } |
551 | | |
552 | | static void Ap_indexOf(js_State *J) |
553 | 0 | { |
554 | 0 | int k, len, from; |
555 | |
|
556 | 0 | len = js_getlength(J, 0); |
557 | 0 | from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0; |
558 | 0 | if (from < 0) from = len + from; |
559 | 0 | if (from < 0) from = 0; |
560 | |
|
561 | 0 | js_copy(J, 1); |
562 | 0 | for (k = from; k < len; ++k) { |
563 | 0 | if (js_hasindex(J, 0, k)) { |
564 | 0 | if (js_strictequal(J)) { |
565 | 0 | js_pushnumber(J, k); |
566 | 0 | return; |
567 | 0 | } |
568 | 0 | js_pop(J, 1); |
569 | 0 | } |
570 | 0 | } |
571 | | |
572 | 0 | js_pushnumber(J, -1); |
573 | 0 | } |
574 | | |
575 | | static void Ap_lastIndexOf(js_State *J) |
576 | 0 | { |
577 | 0 | int k, len, from; |
578 | |
|
579 | 0 | len = js_getlength(J, 0); |
580 | 0 | from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1; |
581 | 0 | if (from > len - 1) from = len - 1; |
582 | 0 | if (from < 0) from = len + from; |
583 | |
|
584 | 0 | js_copy(J, 1); |
585 | 0 | for (k = from; k >= 0; --k) { |
586 | 0 | if (js_hasindex(J, 0, k)) { |
587 | 0 | if (js_strictequal(J)) { |
588 | 0 | js_pushnumber(J, k); |
589 | 0 | return; |
590 | 0 | } |
591 | 0 | js_pop(J, 1); |
592 | 0 | } |
593 | 0 | } |
594 | | |
595 | 0 | js_pushnumber(J, -1); |
596 | 0 | } |
597 | | |
598 | | static void Ap_every(js_State *J) |
599 | 0 | { |
600 | 0 | int hasthis = js_gettop(J) >= 3; |
601 | 0 | int k, len; |
602 | |
|
603 | 0 | if (!js_iscallable(J, 1)) |
604 | 0 | js_typeerror(J, "callback is not a function"); |
605 | | |
606 | 0 | len = js_getlength(J, 0); |
607 | 0 | for (k = 0; k < len; ++k) { |
608 | 0 | if (js_hasindex(J, 0, k)) { |
609 | 0 | js_copy(J, 1); |
610 | 0 | if (hasthis) |
611 | 0 | js_copy(J, 2); |
612 | 0 | else |
613 | 0 | js_pushundefined(J); |
614 | 0 | js_copy(J, -3); |
615 | 0 | js_pushnumber(J, k); |
616 | 0 | js_copy(J, 0); |
617 | 0 | js_call(J, 3); |
618 | 0 | if (!js_toboolean(J, -1)) |
619 | 0 | return; |
620 | 0 | js_pop(J, 2); |
621 | 0 | } |
622 | 0 | } |
623 | | |
624 | 0 | js_pushboolean(J, 1); |
625 | 0 | } |
626 | | |
627 | | static void Ap_some(js_State *J) |
628 | 0 | { |
629 | 0 | int hasthis = js_gettop(J) >= 3; |
630 | 0 | int k, len; |
631 | |
|
632 | 0 | if (!js_iscallable(J, 1)) |
633 | 0 | js_typeerror(J, "callback is not a function"); |
634 | | |
635 | 0 | len = js_getlength(J, 0); |
636 | 0 | for (k = 0; k < len; ++k) { |
637 | 0 | if (js_hasindex(J, 0, k)) { |
638 | 0 | js_copy(J, 1); |
639 | 0 | if (hasthis) |
640 | 0 | js_copy(J, 2); |
641 | 0 | else |
642 | 0 | js_pushundefined(J); |
643 | 0 | js_copy(J, -3); |
644 | 0 | js_pushnumber(J, k); |
645 | 0 | js_copy(J, 0); |
646 | 0 | js_call(J, 3); |
647 | 0 | if (js_toboolean(J, -1)) |
648 | 0 | return; |
649 | 0 | js_pop(J, 2); |
650 | 0 | } |
651 | 0 | } |
652 | | |
653 | 0 | js_pushboolean(J, 0); |
654 | 0 | } |
655 | | |
656 | | static void Ap_forEach(js_State *J) |
657 | 0 | { |
658 | 0 | int hasthis = js_gettop(J) >= 3; |
659 | 0 | int k, len; |
660 | |
|
661 | 0 | if (!js_iscallable(J, 1)) |
662 | 0 | js_typeerror(J, "callback is not a function"); |
663 | | |
664 | 0 | len = js_getlength(J, 0); |
665 | 0 | for (k = 0; k < len; ++k) { |
666 | 0 | if (js_hasindex(J, 0, k)) { |
667 | 0 | js_copy(J, 1); |
668 | 0 | if (hasthis) |
669 | 0 | js_copy(J, 2); |
670 | 0 | else |
671 | 0 | js_pushundefined(J); |
672 | 0 | js_copy(J, -3); |
673 | 0 | js_pushnumber(J, k); |
674 | 0 | js_copy(J, 0); |
675 | 0 | js_call(J, 3); |
676 | 0 | js_pop(J, 2); |
677 | 0 | } |
678 | 0 | } |
679 | |
|
680 | 0 | js_pushundefined(J); |
681 | 0 | } |
682 | | |
683 | | static void Ap_map(js_State *J) |
684 | 0 | { |
685 | 0 | int hasthis = js_gettop(J) >= 3; |
686 | 0 | int k, len; |
687 | |
|
688 | 0 | if (!js_iscallable(J, 1)) |
689 | 0 | js_typeerror(J, "callback is not a function"); |
690 | | |
691 | 0 | js_newarray(J); |
692 | |
|
693 | 0 | len = js_getlength(J, 0); |
694 | 0 | for (k = 0; k < len; ++k) { |
695 | 0 | if (js_hasindex(J, 0, k)) { |
696 | 0 | js_copy(J, 1); |
697 | 0 | if (hasthis) |
698 | 0 | js_copy(J, 2); |
699 | 0 | else |
700 | 0 | js_pushundefined(J); |
701 | 0 | js_copy(J, -3); |
702 | 0 | js_pushnumber(J, k); |
703 | 0 | js_copy(J, 0); |
704 | 0 | js_call(J, 3); |
705 | 0 | js_setindex(J, -3, k); |
706 | 0 | js_pop(J, 1); |
707 | 0 | } |
708 | 0 | } |
709 | 0 | js_setlength(J, -1, len); |
710 | 0 | } |
711 | | |
712 | | static void Ap_filter(js_State *J) |
713 | 0 | { |
714 | 0 | int hasthis = js_gettop(J) >= 3; |
715 | 0 | int k, to, len; |
716 | |
|
717 | 0 | if (!js_iscallable(J, 1)) |
718 | 0 | js_typeerror(J, "callback is not a function"); |
719 | | |
720 | 0 | js_newarray(J); |
721 | 0 | to = 0; |
722 | |
|
723 | 0 | len = js_getlength(J, 0); |
724 | 0 | for (k = 0; k < len; ++k) { |
725 | 0 | if (js_hasindex(J, 0, k)) { |
726 | 0 | js_copy(J, 1); |
727 | 0 | if (hasthis) |
728 | 0 | js_copy(J, 2); |
729 | 0 | else |
730 | 0 | js_pushundefined(J); |
731 | 0 | js_copy(J, -3); |
732 | 0 | js_pushnumber(J, k); |
733 | 0 | js_copy(J, 0); |
734 | 0 | js_call(J, 3); |
735 | 0 | if (js_toboolean(J, -1)) { |
736 | 0 | js_pop(J, 1); |
737 | 0 | js_setindex(J, -2, to++); |
738 | 0 | } else { |
739 | 0 | js_pop(J, 2); |
740 | 0 | } |
741 | 0 | } |
742 | 0 | } |
743 | 0 | } |
744 | | |
745 | | static void Ap_reduce(js_State *J) |
746 | 0 | { |
747 | 0 | int hasinitial = js_gettop(J) >= 3; |
748 | 0 | int k, len; |
749 | |
|
750 | 0 | if (!js_iscallable(J, 1)) |
751 | 0 | js_typeerror(J, "callback is not a function"); |
752 | | |
753 | 0 | len = js_getlength(J, 0); |
754 | 0 | k = 0; |
755 | |
|
756 | 0 | if (len == 0 && !hasinitial) |
757 | 0 | js_typeerror(J, "no initial value"); |
758 | | |
759 | | /* initial value of accumulator */ |
760 | 0 | if (hasinitial) |
761 | 0 | js_copy(J, 2); |
762 | 0 | else { |
763 | 0 | while (k < len) |
764 | 0 | if (js_hasindex(J, 0, k++)) |
765 | 0 | break; |
766 | 0 | if (k == len) |
767 | 0 | js_typeerror(J, "no initial value"); |
768 | 0 | } |
769 | | |
770 | 0 | while (k < len) { |
771 | 0 | if (js_hasindex(J, 0, k)) { |
772 | 0 | js_copy(J, 1); |
773 | 0 | js_pushundefined(J); |
774 | 0 | js_rot(J, 4); /* accumulator on top */ |
775 | 0 | js_rot(J, 4); /* property on top */ |
776 | 0 | js_pushnumber(J, k); |
777 | 0 | js_copy(J, 0); |
778 | 0 | js_call(J, 4); /* calculate new accumulator */ |
779 | 0 | } |
780 | 0 | ++k; |
781 | 0 | } |
782 | | |
783 | | /* return accumulator */ |
784 | 0 | } |
785 | | |
786 | | static void Ap_reduceRight(js_State *J) |
787 | 0 | { |
788 | 0 | int hasinitial = js_gettop(J) >= 3; |
789 | 0 | int k, len; |
790 | |
|
791 | 0 | if (!js_iscallable(J, 1)) |
792 | 0 | js_typeerror(J, "callback is not a function"); |
793 | | |
794 | 0 | len = js_getlength(J, 0); |
795 | 0 | k = len - 1; |
796 | |
|
797 | 0 | if (len == 0 && !hasinitial) |
798 | 0 | js_typeerror(J, "no initial value"); |
799 | | |
800 | | /* initial value of accumulator */ |
801 | 0 | if (hasinitial) |
802 | 0 | js_copy(J, 2); |
803 | 0 | else { |
804 | 0 | while (k >= 0) |
805 | 0 | if (js_hasindex(J, 0, k--)) |
806 | 0 | break; |
807 | 0 | if (k < 0) |
808 | 0 | js_typeerror(J, "no initial value"); |
809 | 0 | } |
810 | | |
811 | 0 | while (k >= 0) { |
812 | 0 | if (js_hasindex(J, 0, k)) { |
813 | 0 | js_copy(J, 1); |
814 | 0 | js_pushundefined(J); |
815 | 0 | js_rot(J, 4); /* accumulator on top */ |
816 | 0 | js_rot(J, 4); /* property on top */ |
817 | 0 | js_pushnumber(J, k); |
818 | 0 | js_copy(J, 0); |
819 | 0 | js_call(J, 4); /* calculate new accumulator */ |
820 | 0 | } |
821 | 0 | --k; |
822 | 0 | } |
823 | | |
824 | | /* return accumulator */ |
825 | 0 | } |
826 | | |
827 | | static void A_isArray(js_State *J) |
828 | 0 | { |
829 | 0 | if (js_isobject(J, 1)) { |
830 | 0 | js_Object *T = js_toobject(J, 1); |
831 | 0 | js_pushboolean(J, T->type == JS_CARRAY); |
832 | 0 | } else { |
833 | 0 | js_pushboolean(J, 0); |
834 | 0 | } |
835 | 0 | } |
836 | | |
837 | | void jsB_initarray(js_State *J) |
838 | 0 | { |
839 | 0 | js_pushobject(J, J->Array_prototype); |
840 | 0 | { |
841 | 0 | jsB_propf(J, "Array.prototype.toString", Ap_toString, 0); |
842 | 0 | jsB_propf(J, "Array.prototype.concat", Ap_concat, 0); /* 1 */ |
843 | 0 | jsB_propf(J, "Array.prototype.join", Ap_join, 1); |
844 | 0 | jsB_propf(J, "Array.prototype.pop", Ap_pop, 0); |
845 | 0 | jsB_propf(J, "Array.prototype.push", Ap_push, 0); /* 1 */ |
846 | 0 | jsB_propf(J, "Array.prototype.reverse", Ap_reverse, 0); |
847 | 0 | jsB_propf(J, "Array.prototype.shift", Ap_shift, 0); |
848 | 0 | jsB_propf(J, "Array.prototype.slice", Ap_slice, 2); |
849 | 0 | jsB_propf(J, "Array.prototype.sort", Ap_sort, 1); |
850 | 0 | jsB_propf(J, "Array.prototype.splice", Ap_splice, 2); |
851 | 0 | jsB_propf(J, "Array.prototype.unshift", Ap_unshift, 0); /* 1 */ |
852 | | |
853 | | /* ES5 */ |
854 | 0 | jsB_propf(J, "Array.prototype.indexOf", Ap_indexOf, 1); |
855 | 0 | jsB_propf(J, "Array.prototype.lastIndexOf", Ap_lastIndexOf, 1); |
856 | 0 | jsB_propf(J, "Array.prototype.every", Ap_every, 1); |
857 | 0 | jsB_propf(J, "Array.prototype.some", Ap_some, 1); |
858 | 0 | jsB_propf(J, "Array.prototype.forEach", Ap_forEach, 1); |
859 | 0 | jsB_propf(J, "Array.prototype.map", Ap_map, 1); |
860 | 0 | jsB_propf(J, "Array.prototype.filter", Ap_filter, 1); |
861 | 0 | jsB_propf(J, "Array.prototype.reduce", Ap_reduce, 1); |
862 | 0 | jsB_propf(J, "Array.prototype.reduceRight", Ap_reduceRight, 1); |
863 | 0 | } |
864 | 0 | js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 0); /* 1 */ |
865 | 0 | { |
866 | | /* ES5 */ |
867 | 0 | jsB_propf(J, "Array.isArray", A_isArray, 1); |
868 | 0 | } |
869 | 0 | js_defglobal(J, "Array", JS_DONTENUM); |
870 | 0 | } |