Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7641 views
1
#include "jsi.h"
2
#include "jsvalue.h"
3
#include "jsbuiltin.h"
4
5
unsigned int js_getlength(js_State *J, int idx)
6
{
7
unsigned int len;
8
js_getproperty(J, idx, "length");
9
len = js_touint32(J, -1);
10
js_pop(J, 1);
11
return len;
12
}
13
14
void js_setlength(js_State *J, int idx, unsigned int len)
15
{
16
js_pushnumber(J, len);
17
js_setproperty(J, idx < 0 ? idx - 1: idx, "length");
18
}
19
20
int js_hasindex(js_State *J, int idx, unsigned int i)
21
{
22
char buf[32];
23
return js_hasproperty(J, idx, js_itoa(buf, i));
24
}
25
26
void js_getindex(js_State *J, int idx, unsigned int i)
27
{
28
char buf[32];
29
js_getproperty(J, idx, js_itoa(buf, i));
30
}
31
32
void js_setindex(js_State *J, int idx, unsigned int i)
33
{
34
char buf[32];
35
js_setproperty(J, idx, js_itoa(buf, i));
36
}
37
38
void js_delindex(js_State *J, int idx, unsigned int i)
39
{
40
char buf[32];
41
js_delproperty(J, idx, js_itoa(buf, i));
42
}
43
44
static void jsB_new_Array(js_State *J)
45
{
46
unsigned int i, top = js_gettop(J);
47
48
js_newarray(J);
49
50
if (top == 2) {
51
if (js_isnumber(J, 1)) {
52
js_copy(J, 1);
53
js_setproperty(J, -2, "length");
54
} else {
55
js_copy(J, 1);
56
js_setindex(J, -2, 0);
57
}
58
} else {
59
for (i = 1; i < top; ++i) {
60
js_copy(J, i);
61
js_setindex(J, -2, i - 1);
62
}
63
}
64
}
65
66
static void Ap_concat(js_State *J)
67
{
68
unsigned int i, top = js_gettop(J);
69
unsigned int n, k, len;
70
71
js_newarray(J);
72
n = 0;
73
74
for (i = 0; i < top; ++i) {
75
js_copy(J, i);
76
if (js_isarray(J, -1)) {
77
len = js_getlength(J, -1);
78
for (k = 0; k < len; ++k)
79
if (js_hasindex(J, -1, k))
80
js_setindex(J, -3, n++);
81
js_pop(J, 1);
82
} else {
83
js_setindex(J, -2, n++);
84
}
85
}
86
}
87
88
static void Ap_join(js_State *J)
89
{
90
char * volatile out = NULL;
91
const char *sep;
92
const char *r;
93
unsigned int seplen;
94
unsigned int k, n, len;
95
96
len = js_getlength(J, 0);
97
98
if (js_isdefined(J, 1)) {
99
sep = js_tostring(J, 1);
100
seplen = strlen(sep);
101
} else {
102
sep = ",";
103
seplen = 1;
104
}
105
106
if (len == 0) {
107
js_pushliteral(J, "");
108
return;
109
}
110
111
if (js_try(J)) {
112
js_free(J, out);
113
js_throw(J);
114
}
115
116
n = 1;
117
for (k = 0; k < len; ++k) {
118
js_getindex(J, 0, k);
119
if (js_isundefined(J, -1) || js_isnull(J, -1))
120
r = "";
121
else
122
r = js_tostring(J, -1);
123
n += strlen(r);
124
125
if (k == 0) {
126
out = js_malloc(J, n);
127
strcpy(out, r);
128
} else {
129
n += seplen;
130
out = realloc(out, n);
131
strcat(out, sep);
132
strcat(out, r);
133
}
134
135
js_pop(J, 1);
136
}
137
138
js_pushstring(J, out);
139
js_endtry(J);
140
js_free(J, out);
141
}
142
143
static void Ap_pop(js_State *J)
144
{
145
unsigned int n;
146
147
n = js_getlength(J, 0);
148
149
if (n > 0) {
150
js_getindex(J, 0, n - 1);
151
js_delindex(J, 0, n - 1);
152
js_setlength(J, 0, n - 1);
153
} else {
154
js_setlength(J, 0, 0);
155
js_pushundefined(J);
156
}
157
}
158
159
static void Ap_push(js_State *J)
160
{
161
unsigned int i, top = js_gettop(J);
162
unsigned int n;
163
164
n = js_getlength(J, 0);
165
166
for (i = 1; i < top; ++i, ++n) {
167
js_copy(J, i);
168
js_setindex(J, 0, n);
169
}
170
171
js_setlength(J, 0, n);
172
173
js_pushnumber(J, n);
174
}
175
176
static void Ap_reverse(js_State *J)
177
{
178
unsigned int len, middle, lower;
179
180
len = js_getlength(J, 0);
181
middle = len / 2;
182
lower = 0;
183
184
while (lower != middle) {
185
unsigned int upper = len - lower - 1;
186
int haslower = js_hasindex(J, 0, lower);
187
int hasupper = js_hasindex(J, 0, upper);
188
if (haslower && hasupper) {
189
js_setindex(J, 0, lower);
190
js_setindex(J, 0, upper);
191
} else if (hasupper) {
192
js_setindex(J, 0, lower);
193
js_delindex(J, 0, upper);
194
} else if (haslower) {
195
js_setindex(J, 0, upper);
196
js_delindex(J, 0, lower);
197
}
198
++lower;
199
}
200
201
js_copy(J, 0);
202
}
203
204
static void Ap_shift(js_State *J)
205
{
206
unsigned int k, len;
207
208
len = js_getlength(J, 0);
209
210
if (len == 0) {
211
js_setlength(J, 0, 0);
212
js_pushundefined(J);
213
return;
214
}
215
216
js_getindex(J, 0, 0);
217
218
for (k = 1; k < len; ++k) {
219
if (js_hasindex(J, 0, k))
220
js_setindex(J, 0, k - 1);
221
else
222
js_delindex(J, 0, k - 1);
223
}
224
225
js_delindex(J, 0, len - 1);
226
js_setlength(J, 0, len - 1);
227
}
228
229
static void Ap_slice(js_State *J)
230
{
231
unsigned int len, s, e, n;
232
double sv, ev;
233
234
js_newarray(J);
235
236
len = js_getlength(J, 0);
237
sv = js_tointeger(J, 1);
238
ev = js_isdefined(J, 2) ? js_tointeger(J, 2) : len;
239
240
if (sv < 0) sv = sv + len;
241
if (ev < 0) ev = ev + len;
242
243
s = sv < 0 ? 0 : sv > len ? len : sv;
244
e = ev < 0 ? 0 : ev > len ? len : ev;
245
246
for (n = 0; s < e; ++s, ++n)
247
if (js_hasindex(J, 0, s))
248
js_setindex(J, -2, n);
249
}
250
251
static int compare(js_State *J, unsigned int x, unsigned int y, int *hasx, int *hasy, int hasfn)
252
{
253
const char *sx, *sy;
254
int c;
255
256
*hasx = js_hasindex(J, 0, x);
257
*hasy = js_hasindex(J, 0, y);
258
259
if (*hasx && *hasy) {
260
int unx = js_isundefined(J, -2);
261
int uny = js_isundefined(J, -1);
262
if (unx && uny) return 0;
263
if (unx) return 1;
264
if (uny) return -1;
265
266
if (hasfn) {
267
js_copy(J, 1); /* copy function */
268
js_pushundefinedthis(J); /* set this object */
269
js_copy(J, -4); /* copy x */
270
js_copy(J, -4); /* copy y */
271
js_call(J, 2);
272
c = js_tonumber(J, -1);
273
js_pop(J, 1);
274
return c;
275
}
276
277
sx = js_tostring(J, -2);
278
sy = js_tostring(J, -1);
279
return strcmp(sx, sy);
280
}
281
282
if (*hasx) return -1;
283
if (*hasy) return 1;
284
return 0;
285
}
286
287
static void Ap_sort(js_State *J)
288
{
289
unsigned int len, i, k;
290
int hasx, hasy, hasfn;
291
292
len = js_getlength(J, 0);
293
294
hasfn = js_iscallable(J, 1);
295
296
for (i = 1; i < len; ++i) {
297
k = i;
298
while (k > 0 && compare(J, k - 1, k, &hasx, &hasy, hasfn) > 0) {
299
if (hasx && hasy) {
300
js_setindex(J, 0, k - 1);
301
js_setindex(J, 0, k);
302
} else if (hasx) {
303
js_delindex(J, 0, k - 1);
304
js_setindex(J, 0, k);
305
} else if (hasy) {
306
js_setindex(J, 0, k - 1);
307
js_delindex(J, 0, k);
308
}
309
--k;
310
}
311
}
312
313
js_copy(J, 0);
314
}
315
316
static void Ap_splice(js_State *J)
317
{
318
unsigned int top = js_gettop(J);
319
unsigned int len, start, del, add, k;
320
double f;
321
322
js_newarray(J);
323
324
len = js_getlength(J, 0);
325
326
f = js_tointeger(J, 1);
327
if (f < 0) f = f + len;
328
start = f < 0 ? 0 : f > len ? len : f;
329
330
f = js_tointeger(J, 2);
331
del = f < 0 ? 0 : f > len - start ? len - start : f;
332
333
/* copy deleted items to return array */
334
for (k = 0; k < del; ++k)
335
if (js_hasindex(J, 0, start + k))
336
js_setindex(J, -2, k);
337
js_setlength(J, -1, del);
338
339
/* shift the tail to resize the hole left by deleted items */
340
add = top - 3;
341
if (add < del) {
342
for (k = start; k < len - del; ++k) {
343
if (js_hasindex(J, 0, k + del))
344
js_setindex(J, 0, k + add);
345
else
346
js_delindex(J, 0, k + add);
347
}
348
for (k = len; k > len - del + add; --k)
349
js_delindex(J, 0, k - 1);
350
} else if (add > del) {
351
for (k = len - del; k > start; --k) {
352
if (js_hasindex(J, 0, k + del - 1))
353
js_setindex(J, 0, k + add - 1);
354
else
355
js_delindex(J, 0, k + add - 1);
356
}
357
}
358
359
/* copy new items into the hole */
360
for (k = 0; k < add; ++k) {
361
js_copy(J, 3 + k);
362
js_setindex(J, 0, start + k);
363
}
364
365
js_setlength(J, 0, len - del + add);
366
}
367
368
static void Ap_unshift(js_State *J)
369
{
370
unsigned int i, top = js_gettop(J);
371
unsigned int k, len;
372
373
len = js_getlength(J, 0);
374
375
for (k = len; k > 0; --k) {
376
int from = k - 1;
377
int to = k + top - 2;
378
if (js_hasindex(J, 0, from))
379
js_setindex(J, 0, to);
380
else
381
js_delindex(J, 0, to);
382
}
383
384
for (i = 1; i < top; ++i) {
385
js_copy(J, i);
386
js_setindex(J, 0, i - 1);
387
}
388
389
js_setlength(J, 0, len + top - 1);
390
391
js_pushnumber(J, len + top - 1);
392
}
393
394
static void Ap_toString(js_State *J)
395
{
396
unsigned int top = js_gettop(J);
397
js_pop(J, top - 1);
398
Ap_join(J);
399
}
400
401
static void Ap_indexOf(js_State *J)
402
{
403
int k, len, from;
404
405
len = js_getlength(J, 0);
406
from = js_isdefined(J, 2) ? js_tointeger(J, 2) : 0;
407
if (from < 0) from = len + from;
408
if (from < 0) from = 0;
409
410
js_copy(J, 1);
411
for (k = from; k < len; ++k) {
412
if (js_hasindex(J, 0, k)) {
413
if (js_strictequal(J)) {
414
js_pushnumber(J, k);
415
return;
416
}
417
js_pop(J, 1);
418
}
419
}
420
421
js_pushnumber(J, -1);
422
}
423
424
static void Ap_lastIndexOf(js_State *J)
425
{
426
int k, len, from;
427
428
len = js_getlength(J, 0);
429
from = js_isdefined(J, 2) ? js_tointeger(J, 2) : len - 1;
430
if (from > len - 1) from = len - 1;
431
if (from < 0) from = len + from;
432
433
js_copy(J, 1);
434
for (k = from; k >= 0; --k) {
435
if (js_hasindex(J, 0, k)) {
436
if (js_strictequal(J)) {
437
js_pushnumber(J, k);
438
return;
439
}
440
js_pop(J, 1);
441
}
442
}
443
444
js_pushnumber(J, -1);
445
}
446
447
static void Ap_every(js_State *J)
448
{
449
int hasthis = js_gettop(J) >= 3;
450
int k, len;
451
452
if (!js_iscallable(J, 1))
453
js_typeerror(J, "callback is not a function");
454
455
len = js_getlength(J, 0);
456
for (k = 0; k < len; ++k) {
457
if (js_hasindex(J, 0, k)) {
458
js_copy(J, 1);
459
if (hasthis)
460
js_copy(J, 2);
461
else
462
js_pushundefined(J);
463
js_copy(J, -3);
464
js_pushnumber(J, k);
465
js_copy(J, 0);
466
js_call(J, 3);
467
if (!js_toboolean(J, -1))
468
return;
469
js_pop(J, 2);
470
}
471
}
472
473
js_pushboolean(J, 1);
474
}
475
476
static void Ap_some(js_State *J)
477
{
478
int hasthis = js_gettop(J) >= 3;
479
int k, len;
480
481
if (!js_iscallable(J, 1))
482
js_typeerror(J, "callback is not a function");
483
484
len = js_getlength(J, 0);
485
for (k = 0; k < len; ++k) {
486
if (js_hasindex(J, 0, k)) {
487
js_copy(J, 1);
488
if (hasthis)
489
js_copy(J, 2);
490
else
491
js_pushundefined(J);
492
js_copy(J, -3);
493
js_pushnumber(J, k);
494
js_copy(J, 0);
495
js_call(J, 3);
496
if (js_toboolean(J, -1))
497
return;
498
js_pop(J, 2);
499
}
500
}
501
502
js_pushboolean(J, 0);
503
}
504
505
static void Ap_forEach(js_State *J)
506
{
507
int hasthis = js_gettop(J) >= 3;
508
int k, len;
509
510
if (!js_iscallable(J, 1))
511
js_typeerror(J, "callback is not a function");
512
513
len = js_getlength(J, 0);
514
for (k = 0; k < len; ++k) {
515
if (js_hasindex(J, 0, k)) {
516
js_copy(J, 1);
517
if (hasthis)
518
js_copy(J, 2);
519
else
520
js_pushundefined(J);
521
js_copy(J, -3);
522
js_pushnumber(J, k);
523
js_copy(J, 0);
524
js_call(J, 3);
525
js_pop(J, 2);
526
}
527
}
528
529
js_pushundefined(J);
530
}
531
532
static void Ap_map(js_State *J)
533
{
534
int hasthis = js_gettop(J) >= 3;
535
int k, len;
536
537
if (!js_iscallable(J, 1))
538
js_typeerror(J, "callback is not a function");
539
540
js_newarray(J);
541
542
len = js_getlength(J, 0);
543
for (k = 0; k < len; ++k) {
544
if (js_hasindex(J, 0, k)) {
545
js_copy(J, 1);
546
if (hasthis)
547
js_copy(J, 2);
548
else
549
js_pushundefined(J);
550
js_copy(J, -3);
551
js_pushnumber(J, k);
552
js_copy(J, 0);
553
js_call(J, 3);
554
js_setindex(J, -3, k);
555
js_pop(J, 1);
556
}
557
}
558
}
559
560
static void Ap_filter(js_State *J)
561
{
562
int hasthis = js_gettop(J) >= 3;
563
int k, to, len;
564
565
if (!js_iscallable(J, 1))
566
js_typeerror(J, "callback is not a function");
567
568
js_newarray(J);
569
to = 0;
570
571
len = js_getlength(J, 0);
572
for (k = 0; k < len; ++k) {
573
if (js_hasindex(J, 0, k)) {
574
js_copy(J, 1);
575
if (hasthis)
576
js_copy(J, 2);
577
else
578
js_pushundefined(J);
579
js_copy(J, -3);
580
js_pushnumber(J, k);
581
js_copy(J, 0);
582
js_call(J, 3);
583
if (js_toboolean(J, -1)) {
584
js_pop(J, 1);
585
js_setindex(J, -2, to++);
586
} else {
587
js_pop(J, 2);
588
}
589
}
590
}
591
}
592
593
static void Ap_reduce(js_State *J)
594
{
595
int hasinitial = js_gettop(J) >= 3;
596
int k, len;
597
598
if (!js_iscallable(J, 1))
599
js_typeerror(J, "callback is not a function");
600
601
len = js_getlength(J, 0);
602
k = 0;
603
604
if (len == 0 && !hasinitial)
605
js_typeerror(J, "no initial value");
606
607
/* initial value of accumulator */
608
if (hasinitial)
609
js_copy(J, 2);
610
else {
611
while (k < len)
612
if (js_hasindex(J, 0, k++))
613
break;
614
if (k == len)
615
js_typeerror(J, "no initial value");
616
}
617
618
while (k < len) {
619
if (js_hasindex(J, 0, k)) {
620
js_copy(J, 1);
621
js_pushundefined(J);
622
js_rot(J, 4); /* accumulator on top */
623
js_rot(J, 4); /* property on top */
624
js_pushnumber(J, k);
625
js_copy(J, 0);
626
js_call(J, 4); /* calculate new accumulator */
627
}
628
++k;
629
}
630
631
/* return accumulator */
632
}
633
634
static void Ap_reduceRight(js_State *J)
635
{
636
int hasinitial = js_gettop(J) >= 3;
637
int k, len;
638
639
if (!js_iscallable(J, 1))
640
js_typeerror(J, "callback is not a function");
641
642
len = js_getlength(J, 0);
643
k = len - 1;
644
645
if (len == 0 && !hasinitial)
646
js_typeerror(J, "no initial value");
647
648
/* initial value of accumulator */
649
if (hasinitial)
650
js_copy(J, 2);
651
else {
652
while (k >= 0)
653
if (js_hasindex(J, 0, k--))
654
break;
655
if (k < 0)
656
js_typeerror(J, "no initial value");
657
}
658
659
while (k >= 0) {
660
if (js_hasindex(J, 0, k)) {
661
js_copy(J, 1);
662
js_pushundefined(J);
663
js_rot(J, 4); /* accumulator on top */
664
js_rot(J, 4); /* property on top */
665
js_pushnumber(J, k);
666
js_copy(J, 0);
667
js_call(J, 4); /* calculate new accumulator */
668
}
669
--k;
670
}
671
672
/* return accumulator */
673
}
674
675
static void A_isArray(js_State *J)
676
{
677
if (js_isobject(J, 1)) {
678
js_Object *T = js_toobject(J, 1);
679
js_pushboolean(J, T->type == JS_CARRAY);
680
} else {
681
js_pushboolean(J, 0);
682
}
683
}
684
685
void jsB_initarray(js_State *J)
686
{
687
js_pushobject(J, J->Array_prototype);
688
{
689
jsB_propf(J, "toString", Ap_toString, 0);
690
jsB_propf(J, "concat", Ap_concat, 1);
691
jsB_propf(J, "join", Ap_join, 1);
692
jsB_propf(J, "pop", Ap_pop, 0);
693
jsB_propf(J, "push", Ap_push, 1);
694
jsB_propf(J, "reverse", Ap_reverse, 0);
695
jsB_propf(J, "shift", Ap_shift, 0);
696
jsB_propf(J, "slice", Ap_slice, 2);
697
jsB_propf(J, "sort", Ap_sort, 1);
698
jsB_propf(J, "splice", Ap_splice, 2);
699
jsB_propf(J, "unshift", Ap_unshift, 1);
700
701
/* ES5 */
702
jsB_propf(J, "indexOf", Ap_indexOf, 1);
703
jsB_propf(J, "lastIndexOf", Ap_lastIndexOf, 1);
704
jsB_propf(J, "every", Ap_every, 1);
705
jsB_propf(J, "some", Ap_some, 1);
706
jsB_propf(J, "forEach", Ap_forEach, 1);
707
jsB_propf(J, "map", Ap_map, 1);
708
jsB_propf(J, "filter", Ap_filter, 1);
709
jsB_propf(J, "reduce", Ap_reduce, 1);
710
jsB_propf(J, "reduceRight", Ap_reduceRight, 1);
711
}
712
js_newcconstructor(J, jsB_new_Array, jsB_new_Array, "Array", 1);
713
{
714
/* ES5 */
715
jsB_propf(J, "isArray", A_isArray, 1);
716
}
717
js_defglobal(J, "Array", JS_DONTENUM);
718
}
719
720