comparison mupdf-source/thirdparty/mujs/jscompile.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 #include "jsi.h"
2
3 #define cexp jsC_cexp /* collision with math.h */
4
5 #define JF js_State *J, js_Function *F
6
7 JS_NORETURN void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) JS_PRINTFLIKE(3,4);
8
9 static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body, int is_fun_exp);
10 static void cexp(JF, js_Ast *exp);
11 static void cstmlist(JF, js_Ast *list);
12 static void cstm(JF, js_Ast *stm);
13
14 void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...)
15 {
16 va_list ap;
17 char buf[512];
18 char msgbuf[256];
19
20 va_start(ap, fmt);
21 vsnprintf(msgbuf, 256, fmt, ap);
22 va_end(ap);
23
24 snprintf(buf, 256, "%s:%d: ", J->filename, node->line);
25 strcat(buf, msgbuf);
26
27 js_newsyntaxerror(J, buf);
28 js_throw(J);
29 }
30
31 static const char *futurewords[] = {
32 "class", "const", "enum", "export", "extends", "import", "super",
33 };
34
35 static const char *strictfuturewords[] = {
36 "implements", "interface", "let", "package", "private", "protected",
37 "public", "static", "yield",
38 };
39
40 static void checkfutureword(JF, js_Ast *exp)
41 {
42 if (jsY_findword(exp->string, futurewords, nelem(futurewords)) >= 0)
43 jsC_error(J, exp, "'%s' is a future reserved word", exp->string);
44 if (F->strict) {
45 if (jsY_findword(exp->string, strictfuturewords, nelem(strictfuturewords)) >= 0)
46 jsC_error(J, exp, "'%s' is a strict mode future reserved word", exp->string);
47 }
48 }
49
50 static js_Function *newfun(js_State *J, int line, js_Ast *name, js_Ast *params, js_Ast *body, int script, int default_strict, int is_fun_exp)
51 {
52 js_Function *F = js_malloc(J, sizeof *F);
53 memset(F, 0, sizeof *F);
54 F->gcmark = 0;
55 F->gcnext = J->gcfun;
56 J->gcfun = F;
57 ++J->gccounter;
58
59 F->filename = js_intern(J, J->filename);
60 F->line = line;
61 F->script = script;
62 F->strict = default_strict;
63 F->name = name ? name->string : "";
64
65 cfunbody(J, F, name, params, body, is_fun_exp);
66
67 return F;
68 }
69
70 /* Emit opcodes, constants and jumps */
71
72 static void emitraw(JF, int value)
73 {
74 if (value != (js_Instruction)value)
75 js_syntaxerror(J, "integer overflow in instruction coding");
76 if (F->codelen >= F->codecap) {
77 F->codecap = F->codecap ? F->codecap * 2 : 64;
78 F->code = js_realloc(J, F->code, F->codecap * sizeof *F->code);
79 }
80 F->code[F->codelen++] = value;
81 }
82
83 static void emit(JF, int value)
84 {
85 emitraw(J, F, F->lastline);
86 emitraw(J, F, value);
87 }
88
89 static void emitarg(JF, int value)
90 {
91 emitraw(J, F, value);
92 }
93
94 static void emitline(JF, js_Ast *node)
95 {
96 F->lastline = node->line;
97 }
98
99 static int addfunction(JF, js_Function *value)
100 {
101 if (F->funlen >= F->funcap) {
102 F->funcap = F->funcap ? F->funcap * 2 : 16;
103 F->funtab = js_realloc(J, F->funtab, F->funcap * sizeof *F->funtab);
104 }
105 F->funtab[F->funlen] = value;
106 return F->funlen++;
107 }
108
109 static int addlocal(JF, js_Ast *ident, int reuse)
110 {
111 const char *name = ident->string;
112 if (F->strict) {
113 if (!strcmp(name, "arguments"))
114 jsC_error(J, ident, "redefining 'arguments' is not allowed in strict mode");
115 if (!strcmp(name, "eval"))
116 jsC_error(J, ident, "redefining 'eval' is not allowed in strict mode");
117 } else {
118 if (!strcmp(name, "eval"))
119 js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line);
120 }
121 if (reuse || F->strict) {
122 int i;
123 for (i = 0; i < F->varlen; ++i) {
124 if (!strcmp(F->vartab[i], name)) {
125 if (reuse)
126 return i+1;
127 if (F->strict)
128 jsC_error(J, ident, "duplicate formal parameter '%s'", name);
129 }
130 }
131 }
132 if (F->varlen >= F->varcap) {
133 F->varcap = F->varcap ? F->varcap * 2 : 16;
134 F->vartab = js_realloc(J, F->vartab, F->varcap * sizeof *F->vartab);
135 }
136 F->vartab[F->varlen] = name;
137 return ++F->varlen;
138 }
139
140 static int findlocal(JF, const char *name)
141 {
142 int i;
143 for (i = F->varlen; i > 0; --i)
144 if (!strcmp(F->vartab[i-1], name))
145 return i;
146 return -1;
147 }
148
149 static void emitfunction(JF, js_Function *fun)
150 {
151 F->lightweight = 0;
152 emit(J, F, OP_CLOSURE);
153 emitarg(J, F, addfunction(J, F, fun));
154 }
155
156 static void emitnumber(JF, double num)
157 {
158 if (num == 0) {
159 emit(J, F, OP_INTEGER);
160 emitarg(J, F, 32768);
161 if (signbit(num))
162 emit(J, F, OP_NEG);
163 } else if (num >= SHRT_MIN && num <= SHRT_MAX && num == (int)num) {
164 emit(J, F, OP_INTEGER);
165 emitarg(J, F, num + 32768);
166 } else {
167 #define N (sizeof(num) / sizeof(js_Instruction))
168 js_Instruction x[N];
169 size_t i;
170 emit(J, F, OP_NUMBER);
171 memcpy(x, &num, sizeof(num));
172 for (i = 0; i < N; ++i)
173 emitarg(J, F, x[i]);
174 #undef N
175 }
176 }
177
178 static void emitstring(JF, int opcode, const char *str)
179 {
180 #define N (sizeof(str) / sizeof(js_Instruction))
181 js_Instruction x[N];
182 size_t i;
183 emit(J, F, opcode);
184 memcpy(x, &str, sizeof(str));
185 for (i = 0; i < N; ++i)
186 emitarg(J, F, x[i]);
187 #undef N
188 }
189
190 static void emitlocal(JF, int oploc, int opvar, js_Ast *ident)
191 {
192 int is_arguments = !strcmp(ident->string, "arguments");
193 int is_eval = !strcmp(ident->string, "eval");
194 int i;
195
196 if (is_arguments) {
197 F->lightweight = 0;
198 F->arguments = 1;
199 }
200
201 checkfutureword(J, F, ident);
202 if (F->strict && oploc == OP_SETLOCAL) {
203 if (is_arguments)
204 jsC_error(J, ident, "'arguments' is read-only in strict mode");
205 if (is_eval)
206 jsC_error(J, ident, "'eval' is read-only in strict mode");
207 }
208 if (is_eval)
209 js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line);
210
211 i = findlocal(J, F, ident->string);
212 if (i < 0) {
213 emitstring(J, F, opvar, ident->string);
214 } else {
215 emit(J, F, oploc);
216 emitarg(J, F, i);
217 }
218 }
219
220 static int here(JF)
221 {
222 return F->codelen;
223 }
224
225 static int emitjump(JF, int opcode)
226 {
227 int inst;
228 emit(J, F, opcode);
229 inst = F->codelen;
230 emitarg(J, F, 0);
231 return inst;
232 }
233
234 static void emitjumpto(JF, int opcode, int dest)
235 {
236 emit(J, F, opcode);
237 if (dest != (js_Instruction)dest)
238 js_syntaxerror(J, "jump address integer overflow");
239 emitarg(J, F, dest);
240 }
241
242 static void labelto(JF, int inst, int addr)
243 {
244 if (addr != (js_Instruction)addr)
245 js_syntaxerror(J, "jump address integer overflow");
246 F->code[inst] = addr;
247 }
248
249 static void label(JF, int inst)
250 {
251 labelto(J, F, inst, F->codelen);
252 }
253
254 /* Expressions */
255
256 static void ctypeof(JF, js_Ast *exp)
257 {
258 if (exp->a->type == EXP_IDENTIFIER) {
259 emitline(J, F, exp->a);
260 emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->a);
261 } else {
262 cexp(J, F, exp->a);
263 }
264 emitline(J, F, exp);
265 emit(J, F, OP_TYPEOF);
266 }
267
268 static void cunary(JF, js_Ast *exp, int opcode)
269 {
270 cexp(J, F, exp->a);
271 emitline(J, F, exp);
272 emit(J, F, opcode);
273 }
274
275 static void cbinary(JF, js_Ast *exp, int opcode)
276 {
277 cexp(J, F, exp->a);
278 cexp(J, F, exp->b);
279 emitline(J, F, exp);
280 emit(J, F, opcode);
281 }
282
283 static void carray(JF, js_Ast *list)
284 {
285 while (list) {
286 emitline(J, F, list->a);
287 if (list->a->type == EXP_ELISION) {
288 emit(J, F, OP_SKIPARRAY);
289 } else {
290 cexp(J, F, list->a);
291 emit(J, F, OP_INITARRAY);
292 }
293 list = list->b;
294 }
295 }
296
297 static void checkdup(JF, js_Ast *list, js_Ast *end)
298 {
299 char nbuf[32], sbuf[32];
300 const char *needle, *straw;
301
302 if (end->a->type == EXP_NUMBER)
303 needle = jsV_numbertostring(J, nbuf, end->a->number);
304 else
305 needle = end->a->string;
306
307 while (list->a != end) {
308 if (list->a->type == end->type) {
309 js_Ast *prop = list->a->a;
310 if (prop->type == EXP_NUMBER)
311 straw = jsV_numbertostring(J, sbuf, prop->number);
312 else
313 straw = prop->string;
314 if (!strcmp(needle, straw))
315 jsC_error(J, list, "duplicate property '%s' in object literal", needle);
316 }
317 list = list->b;
318 }
319 }
320
321 static void cobject(JF, js_Ast *list)
322 {
323 js_Ast *head = list;
324
325 while (list) {
326 js_Ast *kv = list->a;
327 js_Ast *prop = kv->a;
328
329 if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING) {
330 emitline(J, F, prop);
331 emitstring(J, F, OP_STRING, prop->string);
332 } else if (prop->type == EXP_NUMBER) {
333 emitline(J, F, prop);
334 emitnumber(J, F, prop->number);
335 } else {
336 jsC_error(J, prop, "invalid property name in object initializer");
337 }
338
339 if (F->strict)
340 checkdup(J, F, head, kv);
341
342 switch (kv->type) {
343 default: /* impossible */ break;
344 case EXP_PROP_VAL:
345 cexp(J, F, kv->b);
346 emitline(J, F, kv);
347 emit(J, F, OP_INITPROP);
348 break;
349 case EXP_PROP_GET:
350 emitfunction(J, F, newfun(J, prop->line, NULL, NULL, kv->c, 0, F->strict, 1));
351 emitline(J, F, kv);
352 emit(J, F, OP_INITGETTER);
353 break;
354 case EXP_PROP_SET:
355 emitfunction(J, F, newfun(J, prop->line, NULL, kv->b, kv->c, 0, F->strict, 1));
356 emitline(J, F, kv);
357 emit(J, F, OP_INITSETTER);
358 break;
359 }
360
361 list = list->b;
362 }
363 }
364
365 static int cargs(JF, js_Ast *list)
366 {
367 int n = 0;
368 while (list) {
369 cexp(J, F, list->a);
370 list = list->b;
371 ++n;
372 }
373 return n;
374 }
375
376 static void cassign(JF, js_Ast *exp)
377 {
378 js_Ast *lhs = exp->a;
379 js_Ast *rhs = exp->b;
380 switch (lhs->type) {
381 case EXP_IDENTIFIER:
382 cexp(J, F, rhs);
383 emitline(J, F, exp);
384 emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);
385 break;
386 case EXP_INDEX:
387 cexp(J, F, lhs->a);
388 cexp(J, F, lhs->b);
389 cexp(J, F, rhs);
390 emitline(J, F, exp);
391 emit(J, F, OP_SETPROP);
392 break;
393 case EXP_MEMBER:
394 cexp(J, F, lhs->a);
395 cexp(J, F, rhs);
396 emitline(J, F, exp);
397 emitstring(J, F, OP_SETPROP_S, lhs->b->string);
398 break;
399 default:
400 jsC_error(J, lhs, "invalid l-value in assignment");
401 }
402 }
403
404 static void cassignforin(JF, js_Ast *stm)
405 {
406 js_Ast *lhs = stm->a;
407
408 if (stm->type == STM_FOR_IN_VAR) {
409 if (lhs->b)
410 jsC_error(J, lhs->b, "more than one loop variable in for-in statement");
411 emitline(J, F, lhs->a);
412 emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs->a->a); /* list(var-init(ident)) */
413 emit(J, F, OP_POP);
414 return;
415 }
416
417 switch (lhs->type) {
418 case EXP_IDENTIFIER:
419 emitline(J, F, lhs);
420 emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);
421 emit(J, F, OP_POP);
422 break;
423 case EXP_INDEX:
424 cexp(J, F, lhs->a);
425 cexp(J, F, lhs->b);
426 emitline(J, F, lhs);
427 emit(J, F, OP_ROT3);
428 emit(J, F, OP_SETPROP);
429 emit(J, F, OP_POP);
430 break;
431 case EXP_MEMBER:
432 cexp(J, F, lhs->a);
433 emitline(J, F, lhs);
434 emit(J, F, OP_ROT2);
435 emitstring(J, F, OP_SETPROP_S, lhs->b->string);
436 emit(J, F, OP_POP);
437 break;
438 default:
439 jsC_error(J, lhs, "invalid l-value in for-in loop assignment");
440 }
441 }
442
443 static void cassignop1(JF, js_Ast *lhs)
444 {
445 switch (lhs->type) {
446 case EXP_IDENTIFIER:
447 emitline(J, F, lhs);
448 emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, lhs);
449 break;
450 case EXP_INDEX:
451 cexp(J, F, lhs->a);
452 cexp(J, F, lhs->b);
453 emitline(J, F, lhs);
454 emit(J, F, OP_DUP2);
455 emit(J, F, OP_GETPROP);
456 break;
457 case EXP_MEMBER:
458 cexp(J, F, lhs->a);
459 emitline(J, F, lhs);
460 emit(J, F, OP_DUP);
461 emitstring(J, F, OP_GETPROP_S, lhs->b->string);
462 break;
463 default:
464 jsC_error(J, lhs, "invalid l-value in assignment");
465 }
466 }
467
468 static void cassignop2(JF, js_Ast *lhs, int postfix)
469 {
470 switch (lhs->type) {
471 case EXP_IDENTIFIER:
472 emitline(J, F, lhs);
473 if (postfix) emit(J, F, OP_ROT2);
474 emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);
475 break;
476 case EXP_INDEX:
477 emitline(J, F, lhs);
478 if (postfix) emit(J, F, OP_ROT4);
479 emit(J, F, OP_SETPROP);
480 break;
481 case EXP_MEMBER:
482 emitline(J, F, lhs);
483 if (postfix) emit(J, F, OP_ROT3);
484 emitstring(J, F, OP_SETPROP_S, lhs->b->string);
485 break;
486 default:
487 jsC_error(J, lhs, "invalid l-value in assignment");
488 }
489 }
490
491 static void cassignop(JF, js_Ast *exp, int opcode)
492 {
493 js_Ast *lhs = exp->a;
494 js_Ast *rhs = exp->b;
495 cassignop1(J, F, lhs);
496 cexp(J, F, rhs);
497 emitline(J, F, exp);
498 emit(J, F, opcode);
499 cassignop2(J, F, lhs, 0);
500 }
501
502 static void cdelete(JF, js_Ast *exp)
503 {
504 js_Ast *arg = exp->a;
505 switch (arg->type) {
506 case EXP_IDENTIFIER:
507 if (F->strict)
508 jsC_error(J, exp, "delete on an unqualified name is not allowed in strict mode");
509 emitline(J, F, exp);
510 emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, arg);
511 break;
512 case EXP_INDEX:
513 cexp(J, F, arg->a);
514 cexp(J, F, arg->b);
515 emitline(J, F, exp);
516 emit(J, F, OP_DELPROP);
517 break;
518 case EXP_MEMBER:
519 cexp(J, F, arg->a);
520 emitline(J, F, exp);
521 emitstring(J, F, OP_DELPROP_S, arg->b->string);
522 break;
523 default:
524 jsC_error(J, exp, "invalid l-value in delete expression");
525 }
526 }
527
528 static void ceval(JF, js_Ast *fun, js_Ast *args)
529 {
530 int n = cargs(J, F, args);
531 F->lightweight = 0;
532 F->arguments = 1;
533 if (n == 0)
534 emit(J, F, OP_UNDEF);
535 else while (n-- > 1)
536 emit(J, F, OP_POP);
537 emit(J, F, OP_EVAL);
538 }
539
540 static void ccall(JF, js_Ast *fun, js_Ast *args)
541 {
542 int n;
543 switch (fun->type) {
544 case EXP_INDEX:
545 cexp(J, F, fun->a);
546 emit(J, F, OP_DUP);
547 cexp(J, F, fun->b);
548 emit(J, F, OP_GETPROP);
549 emit(J, F, OP_ROT2);
550 break;
551 case EXP_MEMBER:
552 cexp(J, F, fun->a);
553 emit(J, F, OP_DUP);
554 emitstring(J, F, OP_GETPROP_S, fun->b->string);
555 emit(J, F, OP_ROT2);
556 break;
557 case EXP_IDENTIFIER:
558 if (!strcmp(fun->string, "eval")) {
559 ceval(J, F, fun, args);
560 return;
561 }
562 /* fallthrough */
563 default:
564 cexp(J, F, fun);
565 emit(J, F, OP_UNDEF);
566 break;
567 }
568 n = cargs(J, F, args);
569 emit(J, F, OP_CALL);
570 emitarg(J, F, n);
571 }
572
573 static void cexp(JF, js_Ast *exp)
574 {
575 int then, end;
576 int n;
577
578 switch (exp->type) {
579 case EXP_STRING:
580 emitline(J, F, exp);
581 emitstring(J, F, OP_STRING, exp->string);
582 break;
583 case EXP_NUMBER:
584 emitline(J, F, exp);
585 emitnumber(J, F, exp->number);
586 break;
587 case EXP_ELISION:
588 break;
589 case EXP_NULL:
590 emitline(J, F, exp);
591 emit(J, F, OP_NULL);
592 break;
593 case EXP_TRUE:
594 emitline(J, F, exp);
595 emit(J, F, OP_TRUE);
596 break;
597 case EXP_FALSE:
598 emitline(J, F, exp);
599 emit(J, F, OP_FALSE);
600 break;
601 case EXP_THIS:
602 emitline(J, F, exp);
603 emit(J, F, OP_THIS);
604 break;
605
606 case EXP_REGEXP:
607 emitline(J, F, exp);
608 emitstring(J, F, OP_NEWREGEXP, exp->string);
609 emitarg(J, F, exp->number);
610 break;
611
612 case EXP_OBJECT:
613 emitline(J, F, exp);
614 emit(J, F, OP_NEWOBJECT);
615 cobject(J, F, exp->a);
616 break;
617
618 case EXP_ARRAY:
619 emitline(J, F, exp);
620 emit(J, F, OP_NEWARRAY);
621 carray(J, F, exp->a);
622 break;
623
624 case EXP_FUN:
625 emitline(J, F, exp);
626 emitfunction(J, F, newfun(J, exp->line, exp->a, exp->b, exp->c, 0, F->strict, 1));
627 break;
628
629 case EXP_IDENTIFIER:
630 emitline(J, F, exp);
631 emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp);
632 break;
633
634 case EXP_INDEX:
635 cexp(J, F, exp->a);
636 cexp(J, F, exp->b);
637 emitline(J, F, exp);
638 emit(J, F, OP_GETPROP);
639 break;
640
641 case EXP_MEMBER:
642 cexp(J, F, exp->a);
643 emitline(J, F, exp);
644 emitstring(J, F, OP_GETPROP_S, exp->b->string);
645 break;
646
647 case EXP_CALL:
648 ccall(J, F, exp->a, exp->b);
649 break;
650
651 case EXP_NEW:
652 cexp(J, F, exp->a);
653 n = cargs(J, F, exp->b);
654 emitline(J, F, exp);
655 emit(J, F, OP_NEW);
656 emitarg(J, F, n);
657 break;
658
659 case EXP_DELETE:
660 cdelete(J, F, exp);
661 break;
662
663 case EXP_PREINC:
664 cassignop1(J, F, exp->a);
665 emitline(J, F, exp);
666 emit(J, F, OP_INC);
667 cassignop2(J, F, exp->a, 0);
668 break;
669
670 case EXP_PREDEC:
671 cassignop1(J, F, exp->a);
672 emitline(J, F, exp);
673 emit(J, F, OP_DEC);
674 cassignop2(J, F, exp->a, 0);
675 break;
676
677 case EXP_POSTINC:
678 cassignop1(J, F, exp->a);
679 emitline(J, F, exp);
680 emit(J, F, OP_POSTINC);
681 cassignop2(J, F, exp->a, 1);
682 emit(J, F, OP_POP);
683 break;
684
685 case EXP_POSTDEC:
686 cassignop1(J, F, exp->a);
687 emitline(J, F, exp);
688 emit(J, F, OP_POSTDEC);
689 cassignop2(J, F, exp->a, 1);
690 emit(J, F, OP_POP);
691 break;
692
693 case EXP_VOID:
694 cexp(J, F, exp->a);
695 emitline(J, F, exp);
696 emit(J, F, OP_POP);
697 emit(J, F, OP_UNDEF);
698 break;
699
700 case EXP_TYPEOF: ctypeof(J, F, exp); break;
701 case EXP_POS: cunary(J, F, exp, OP_POS); break;
702 case EXP_NEG: cunary(J, F, exp, OP_NEG); break;
703 case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break;
704 case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break;
705
706 case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break;
707 case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break;
708 case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break;
709 case EXP_EQ: cbinary(J, F, exp, OP_EQ); break;
710 case EXP_NE: cbinary(J, F, exp, OP_NE); break;
711 case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break;
712 case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break;
713 case EXP_LT: cbinary(J, F, exp, OP_LT); break;
714 case EXP_GT: cbinary(J, F, exp, OP_GT); break;
715 case EXP_LE: cbinary(J, F, exp, OP_LE); break;
716 case EXP_GE: cbinary(J, F, exp, OP_GE); break;
717 case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break;
718 case EXP_IN: cbinary(J, F, exp, OP_IN); break;
719 case EXP_SHL: cbinary(J, F, exp, OP_SHL); break;
720 case EXP_SHR: cbinary(J, F, exp, OP_SHR); break;
721 case EXP_USHR: cbinary(J, F, exp, OP_USHR); break;
722 case EXP_ADD: cbinary(J, F, exp, OP_ADD); break;
723 case EXP_SUB: cbinary(J, F, exp, OP_SUB); break;
724 case EXP_MUL: cbinary(J, F, exp, OP_MUL); break;
725 case EXP_DIV: cbinary(J, F, exp, OP_DIV); break;
726 case EXP_MOD: cbinary(J, F, exp, OP_MOD); break;
727
728 case EXP_ASS: cassign(J, F, exp); break;
729 case EXP_ASS_MUL: cassignop(J, F, exp, OP_MUL); break;
730 case EXP_ASS_DIV: cassignop(J, F, exp, OP_DIV); break;
731 case EXP_ASS_MOD: cassignop(J, F, exp, OP_MOD); break;
732 case EXP_ASS_ADD: cassignop(J, F, exp, OP_ADD); break;
733 case EXP_ASS_SUB: cassignop(J, F, exp, OP_SUB); break;
734 case EXP_ASS_SHL: cassignop(J, F, exp, OP_SHL); break;
735 case EXP_ASS_SHR: cassignop(J, F, exp, OP_SHR); break;
736 case EXP_ASS_USHR: cassignop(J, F, exp, OP_USHR); break;
737 case EXP_ASS_BITAND: cassignop(J, F, exp, OP_BITAND); break;
738 case EXP_ASS_BITXOR: cassignop(J, F, exp, OP_BITXOR); break;
739 case EXP_ASS_BITOR: cassignop(J, F, exp, OP_BITOR); break;
740
741 case EXP_COMMA:
742 cexp(J, F, exp->a);
743 emitline(J, F, exp);
744 emit(J, F, OP_POP);
745 cexp(J, F, exp->b);
746 break;
747
748 case EXP_LOGOR:
749 cexp(J, F, exp->a);
750 emitline(J, F, exp);
751 emit(J, F, OP_DUP);
752 end = emitjump(J, F, OP_JTRUE);
753 emit(J, F, OP_POP);
754 cexp(J, F, exp->b);
755 label(J, F, end);
756 break;
757
758 case EXP_LOGAND:
759 cexp(J, F, exp->a);
760 emitline(J, F, exp);
761 emit(J, F, OP_DUP);
762 end = emitjump(J, F, OP_JFALSE);
763 emit(J, F, OP_POP);
764 cexp(J, F, exp->b);
765 label(J, F, end);
766 break;
767
768 case EXP_COND:
769 cexp(J, F, exp->a);
770 emitline(J, F, exp);
771 then = emitjump(J, F, OP_JTRUE);
772 cexp(J, F, exp->c);
773 end = emitjump(J, F, OP_JUMP);
774 label(J, F, then);
775 cexp(J, F, exp->b);
776 label(J, F, end);
777 break;
778
779 default:
780 jsC_error(J, exp, "unknown expression type");
781 }
782 }
783
784 /* Patch break and continue statements */
785
786 static void addjump(JF, enum js_AstType type, js_Ast *target, int inst)
787 {
788 js_JumpList *jump = js_malloc(J, sizeof *jump);
789 jump->type = type;
790 jump->inst = inst;
791 jump->next = target->jumps;
792 target->jumps = jump;
793 }
794
795 static void labeljumps(JF, js_Ast *stm, int baddr, int caddr)
796 {
797 js_JumpList *jump = stm->jumps;
798 while (jump) {
799 js_JumpList *next = jump->next;
800 if (jump->type == STM_BREAK)
801 labelto(J, F, jump->inst, baddr);
802 if (jump->type == STM_CONTINUE)
803 labelto(J, F, jump->inst, caddr);
804 js_free(J, jump);
805 jump = next;
806 }
807 stm->jumps = NULL;
808 }
809
810 static int isloop(enum js_AstType T)
811 {
812 return T == STM_DO || T == STM_WHILE ||
813 T == STM_FOR || T == STM_FOR_VAR ||
814 T == STM_FOR_IN || T == STM_FOR_IN_VAR;
815 }
816
817 static int isfun(enum js_AstType T)
818 {
819 return T == AST_FUNDEC || T == EXP_FUN || T == EXP_PROP_GET || T == EXP_PROP_SET;
820 }
821
822 static int matchlabel(js_Ast *node, const char *label)
823 {
824 while (node && node->type == STM_LABEL) {
825 if (!strcmp(node->a->string, label))
826 return 1;
827 node = node->parent;
828 }
829 return 0;
830 }
831
832 static js_Ast *breaktarget(JF, js_Ast *node, const char *label)
833 {
834 while (node) {
835 if (isfun(node->type))
836 break;
837 if (!label) {
838 if (isloop(node->type) || node->type == STM_SWITCH)
839 return node;
840 } else {
841 if (matchlabel(node->parent, label))
842 return node;
843 }
844 node = node->parent;
845 }
846 return NULL;
847 }
848
849 static js_Ast *continuetarget(JF, js_Ast *node, const char *label)
850 {
851 while (node) {
852 if (isfun(node->type))
853 break;
854 if (isloop(node->type)) {
855 if (!label)
856 return node;
857 else if (matchlabel(node->parent, label))
858 return node;
859 }
860 node = node->parent;
861 }
862 return NULL;
863 }
864
865 static js_Ast *returntarget(JF, js_Ast *node)
866 {
867 while (node) {
868 if (isfun(node->type))
869 return node;
870 node = node->parent;
871 }
872 return NULL;
873 }
874
875 /* Emit code to rebalance stack and scopes during an abrupt exit */
876
877 static void cexit(JF, enum js_AstType T, js_Ast *node, js_Ast *target)
878 {
879 js_Ast *prev;
880 do {
881 prev = node, node = node->parent;
882 switch (node->type) {
883 default:
884 /* impossible */
885 break;
886 case STM_WITH:
887 emitline(J, F, node);
888 emit(J, F, OP_ENDWITH);
889 break;
890 case STM_FOR_IN:
891 case STM_FOR_IN_VAR:
892 emitline(J, F, node);
893 /* pop the iterator if leaving the loop */
894 if (F->script) {
895 if (T == STM_RETURN || T == STM_BREAK || (T == STM_CONTINUE && target != node)) {
896 /* pop the iterator, save the return or exp value */
897 emit(J, F, OP_ROT2);
898 emit(J, F, OP_POP);
899 }
900 if (T == STM_CONTINUE)
901 emit(J, F, OP_ROT2); /* put the iterator back on top */
902 } else {
903 if (T == STM_RETURN) {
904 /* pop the iterator, save the return value */
905 emit(J, F, OP_ROT2);
906 emit(J, F, OP_POP);
907 }
908 if (T == STM_BREAK || (T == STM_CONTINUE && target != node))
909 emit(J, F, OP_POP); /* pop the iterator */
910 }
911 break;
912 case STM_TRY:
913 emitline(J, F, node);
914 /* came from try block */
915 if (prev == node->a) {
916 emit(J, F, OP_ENDTRY);
917 if (node->d) cstm(J, F, node->d); /* finally */
918 }
919 /* came from catch block */
920 if (prev == node->c) {
921 /* ... with finally */
922 if (node->d) {
923 emit(J, F, OP_ENDCATCH);
924 emit(J, F, OP_ENDTRY);
925 cstm(J, F, node->d); /* finally */
926 } else {
927 emit(J, F, OP_ENDCATCH);
928 }
929 }
930 break;
931 }
932 } while (node != target);
933 }
934
935 /* Try/catch/finally */
936
937 static void ctryfinally(JF, js_Ast *trystm, js_Ast *finallystm)
938 {
939 int L1;
940 L1 = emitjump(J, F, OP_TRY);
941 {
942 /* if we get here, we have caught an exception in the try block */
943 cstm(J, F, finallystm); /* inline finally block */
944 emit(J, F, OP_THROW); /* rethrow exception */
945 }
946 label(J, F, L1);
947 cstm(J, F, trystm);
948 emit(J, F, OP_ENDTRY);
949 cstm(J, F, finallystm);
950 }
951
952 static void ctrycatch(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm)
953 {
954 int L1, L2;
955 L1 = emitjump(J, F, OP_TRY);
956 {
957 /* if we get here, we have caught an exception in the try block */
958 checkfutureword(J, F, catchvar);
959 if (F->strict) {
960 if (!strcmp(catchvar->string, "arguments"))
961 jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode");
962 if (!strcmp(catchvar->string, "eval"))
963 jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode");
964 }
965 emitline(J, F, catchvar);
966 emitstring(J, F, OP_CATCH, catchvar->string);
967 cstm(J, F, catchstm);
968 emit(J, F, OP_ENDCATCH);
969 L2 = emitjump(J, F, OP_JUMP); /* skip past the try block */
970 }
971 label(J, F, L1);
972 cstm(J, F, trystm);
973 emit(J, F, OP_ENDTRY);
974 label(J, F, L2);
975 }
976
977 static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm)
978 {
979 int L1, L2, L3;
980 L1 = emitjump(J, F, OP_TRY);
981 {
982 /* if we get here, we have caught an exception in the try block */
983 L2 = emitjump(J, F, OP_TRY);
984 {
985 /* if we get here, we have caught an exception in the catch block */
986 cstm(J, F, finallystm); /* inline finally block */
987 emit(J, F, OP_THROW); /* rethrow exception */
988 }
989 label(J, F, L2);
990 if (F->strict) {
991 checkfutureword(J, F, catchvar);
992 if (!strcmp(catchvar->string, "arguments"))
993 jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode");
994 if (!strcmp(catchvar->string, "eval"))
995 jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode");
996 }
997 emitline(J, F, catchvar);
998 emitstring(J, F, OP_CATCH, catchvar->string);
999 cstm(J, F, catchstm);
1000 emit(J, F, OP_ENDCATCH);
1001 emit(J, F, OP_ENDTRY);
1002 L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */
1003 }
1004 label(J, F, L1);
1005 cstm(J, F, trystm);
1006 emit(J, F, OP_ENDTRY);
1007 label(J, F, L3);
1008 cstm(J, F, finallystm);
1009 }
1010
1011 /* Switch */
1012
1013 static void cswitch(JF, js_Ast *ref, js_Ast *head)
1014 {
1015 js_Ast *node, *clause, *def = NULL;
1016 int end;
1017
1018 cexp(J, F, ref);
1019
1020 /* emit an if-else chain of tests for the case clause expressions */
1021 for (node = head; node; node = node->b) {
1022 clause = node->a;
1023 if (clause->type == STM_DEFAULT) {
1024 if (def)
1025 jsC_error(J, clause, "more than one default label in switch");
1026 def = clause;
1027 } else {
1028 cexp(J, F, clause->a);
1029 emitline(J, F, clause);
1030 clause->casejump = emitjump(J, F, OP_JCASE);
1031 }
1032 }
1033 emit(J, F, OP_POP);
1034 if (def) {
1035 emitline(J, F, def);
1036 def->casejump = emitjump(J, F, OP_JUMP);
1037 end = 0;
1038 } else {
1039 end = emitjump(J, F, OP_JUMP);
1040 }
1041
1042 /* emit the case clause bodies */
1043 for (node = head; node; node = node->b) {
1044 clause = node->a;
1045 label(J, F, clause->casejump);
1046 if (clause->type == STM_DEFAULT)
1047 cstmlist(J, F, clause->a);
1048 else
1049 cstmlist(J, F, clause->b);
1050 }
1051
1052 if (end)
1053 label(J, F, end);
1054 }
1055
1056 /* Statements */
1057
1058 static void cvarinit(JF, js_Ast *list)
1059 {
1060 while (list) {
1061 js_Ast *var = list->a;
1062 if (var->b) {
1063 cexp(J, F, var->b);
1064 emitline(J, F, var);
1065 emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, var->a);
1066 emit(J, F, OP_POP);
1067 }
1068 list = list->b;
1069 }
1070 }
1071
1072 static void cstm(JF, js_Ast *stm)
1073 {
1074 js_Ast *target;
1075 int loop, cont, then, end;
1076
1077 emitline(J, F, stm);
1078
1079 switch (stm->type) {
1080 case AST_FUNDEC:
1081 break;
1082
1083 case STM_BLOCK:
1084 cstmlist(J, F, stm->a);
1085 break;
1086
1087 case STM_EMPTY:
1088 if (F->script) {
1089 emitline(J, F, stm);
1090 emit(J, F, OP_POP);
1091 emit(J, F, OP_UNDEF);
1092 }
1093 break;
1094
1095 case STM_VAR:
1096 cvarinit(J, F, stm->a);
1097 break;
1098
1099 case STM_IF:
1100 if (stm->c) {
1101 cexp(J, F, stm->a);
1102 emitline(J, F, stm);
1103 then = emitjump(J, F, OP_JTRUE);
1104 cstm(J, F, stm->c);
1105 emitline(J, F, stm);
1106 end = emitjump(J, F, OP_JUMP);
1107 label(J, F, then);
1108 cstm(J, F, stm->b);
1109 label(J, F, end);
1110 } else {
1111 cexp(J, F, stm->a);
1112 emitline(J, F, stm);
1113 end = emitjump(J, F, OP_JFALSE);
1114 cstm(J, F, stm->b);
1115 label(J, F, end);
1116 }
1117 break;
1118
1119 case STM_DO:
1120 loop = here(J, F);
1121 cstm(J, F, stm->a);
1122 cont = here(J, F);
1123 cexp(J, F, stm->b);
1124 emitline(J, F, stm);
1125 emitjumpto(J, F, OP_JTRUE, loop);
1126 labeljumps(J, F, stm, here(J,F), cont);
1127 break;
1128
1129 case STM_WHILE:
1130 loop = here(J, F);
1131 cexp(J, F, stm->a);
1132 emitline(J, F, stm);
1133 end = emitjump(J, F, OP_JFALSE);
1134 cstm(J, F, stm->b);
1135 emitline(J, F, stm);
1136 emitjumpto(J, F, OP_JUMP, loop);
1137 label(J, F, end);
1138 labeljumps(J, F, stm, here(J,F), loop);
1139 break;
1140
1141 case STM_FOR:
1142 case STM_FOR_VAR:
1143 if (stm->type == STM_FOR_VAR) {
1144 cvarinit(J, F, stm->a);
1145 } else {
1146 if (stm->a) {
1147 cexp(J, F, stm->a);
1148 emit(J, F, OP_POP);
1149 }
1150 }
1151 loop = here(J, F);
1152 if (stm->b) {
1153 cexp(J, F, stm->b);
1154 emitline(J, F, stm);
1155 end = emitjump(J, F, OP_JFALSE);
1156 } else {
1157 end = 0;
1158 }
1159 cstm(J, F, stm->d);
1160 cont = here(J, F);
1161 if (stm->c) {
1162 cexp(J, F, stm->c);
1163 emit(J, F, OP_POP);
1164 }
1165 emitline(J, F, stm);
1166 emitjumpto(J, F, OP_JUMP, loop);
1167 if (end)
1168 label(J, F, end);
1169 labeljumps(J, F, stm, here(J,F), cont);
1170 break;
1171
1172 case STM_FOR_IN:
1173 case STM_FOR_IN_VAR:
1174 cexp(J, F, stm->b);
1175 emitline(J, F, stm);
1176 emit(J, F, OP_ITERATOR);
1177 loop = here(J, F);
1178 {
1179 emitline(J, F, stm);
1180 emit(J, F, OP_NEXTITER);
1181 end = emitjump(J, F, OP_JFALSE);
1182 cassignforin(J, F, stm);
1183 if (F->script) {
1184 emit(J, F, OP_ROT2);
1185 cstm(J, F, stm->c);
1186 emit(J, F, OP_ROT2);
1187 } else {
1188 cstm(J, F, stm->c);
1189 }
1190 emitline(J, F, stm);
1191 emitjumpto(J, F, OP_JUMP, loop);
1192 }
1193 label(J, F, end);
1194 labeljumps(J, F, stm, here(J,F), loop);
1195 break;
1196
1197 case STM_SWITCH:
1198 cswitch(J, F, stm->a, stm->b);
1199 labeljumps(J, F, stm, here(J,F), 0);
1200 break;
1201
1202 case STM_LABEL:
1203 cstm(J, F, stm->b);
1204 /* skip consecutive labels */
1205 while (stm->type == STM_LABEL)
1206 stm = stm->b;
1207 /* loops and switches have already been labelled */
1208 if (!isloop(stm->type) && stm->type != STM_SWITCH)
1209 labeljumps(J, F, stm, here(J,F), 0);
1210 break;
1211
1212 case STM_BREAK:
1213 if (stm->a) {
1214 checkfutureword(J, F, stm->a);
1215 target = breaktarget(J, F, stm->parent, stm->a->string);
1216 if (!target)
1217 jsC_error(J, stm, "break label '%s' not found", stm->a->string);
1218 } else {
1219 target = breaktarget(J, F, stm->parent, NULL);
1220 if (!target)
1221 jsC_error(J, stm, "unlabelled break must be inside loop or switch");
1222 }
1223 cexit(J, F, STM_BREAK, stm, target);
1224 emitline(J, F, stm);
1225 addjump(J, F, STM_BREAK, target, emitjump(J, F, OP_JUMP));
1226 break;
1227
1228 case STM_CONTINUE:
1229 if (stm->a) {
1230 checkfutureword(J, F, stm->a);
1231 target = continuetarget(J, F, stm->parent, stm->a->string);
1232 if (!target)
1233 jsC_error(J, stm, "continue label '%s' not found", stm->a->string);
1234 } else {
1235 target = continuetarget(J, F, stm->parent, NULL);
1236 if (!target)
1237 jsC_error(J, stm, "continue must be inside loop");
1238 }
1239 cexit(J, F, STM_CONTINUE, stm, target);
1240 emitline(J, F, stm);
1241 addjump(J, F, STM_CONTINUE, target, emitjump(J, F, OP_JUMP));
1242 break;
1243
1244 case STM_RETURN:
1245 if (stm->a)
1246 cexp(J, F, stm->a);
1247 else
1248 emit(J, F, OP_UNDEF);
1249 target = returntarget(J, F, stm->parent);
1250 if (!target)
1251 jsC_error(J, stm, "return not in function");
1252 cexit(J, F, STM_RETURN, stm, target);
1253 emitline(J, F, stm);
1254 emit(J, F, OP_RETURN);
1255 break;
1256
1257 case STM_THROW:
1258 cexp(J, F, stm->a);
1259 emitline(J, F, stm);
1260 emit(J, F, OP_THROW);
1261 break;
1262
1263 case STM_WITH:
1264 F->lightweight = 0;
1265 if (F->strict)
1266 jsC_error(J, stm->a, "'with' statements are not allowed in strict mode");
1267 cexp(J, F, stm->a);
1268 emitline(J, F, stm);
1269 emit(J, F, OP_WITH);
1270 cstm(J, F, stm->b);
1271 emitline(J, F, stm);
1272 emit(J, F, OP_ENDWITH);
1273 break;
1274
1275 case STM_TRY:
1276 emitline(J, F, stm);
1277 if (stm->b && stm->c) {
1278 F->lightweight = 0;
1279 if (stm->d)
1280 ctrycatchfinally(J, F, stm->a, stm->b, stm->c, stm->d);
1281 else
1282 ctrycatch(J, F, stm->a, stm->b, stm->c);
1283 } else {
1284 ctryfinally(J, F, stm->a, stm->d);
1285 }
1286 break;
1287
1288 case STM_DEBUGGER:
1289 emitline(J, F, stm);
1290 emit(J, F, OP_DEBUGGER);
1291 break;
1292
1293 default:
1294 if (F->script) {
1295 emitline(J, F, stm);
1296 emit(J, F, OP_POP);
1297 cexp(J, F, stm);
1298 } else {
1299 cexp(J, F, stm);
1300 emitline(J, F, stm);
1301 emit(J, F, OP_POP);
1302 }
1303 break;
1304 }
1305 }
1306
1307 static void cstmlist(JF, js_Ast *list)
1308 {
1309 while (list) {
1310 cstm(J, F, list->a);
1311 list = list->b;
1312 }
1313 }
1314
1315 /* Declarations and programs */
1316
1317 static int listlength(js_Ast *list)
1318 {
1319 int n = 0;
1320 while (list) ++n, list = list->b;
1321 return n;
1322 }
1323
1324 static void cparams(JF, js_Ast *list, js_Ast *fname)
1325 {
1326 F->numparams = listlength(list);
1327 while (list) {
1328 checkfutureword(J, F, list->a);
1329 addlocal(J, F, list->a, 0);
1330 list = list->b;
1331 }
1332 }
1333
1334 static void cvardecs(JF, js_Ast *node)
1335 {
1336 if (node->type == AST_LIST) {
1337 while (node) {
1338 cvardecs(J, F, node->a);
1339 node = node->b;
1340 }
1341 return;
1342 }
1343
1344 if (isfun(node->type))
1345 return; /* stop at inner functions */
1346
1347 if (node->type == EXP_VAR) {
1348 checkfutureword(J, F, node->a);
1349 addlocal(J, F, node->a, 1);
1350 }
1351
1352 if (node->a) cvardecs(J, F, node->a);
1353 if (node->b) cvardecs(J, F, node->b);
1354 if (node->c) cvardecs(J, F, node->c);
1355 if (node->d) cvardecs(J, F, node->d);
1356 }
1357
1358 static void cfundecs(JF, js_Ast *list)
1359 {
1360 while (list) {
1361 js_Ast *stm = list->a;
1362 if (stm->type == AST_FUNDEC) {
1363 emitline(J, F, stm);
1364 emitfunction(J, F, newfun(J, stm->line, stm->a, stm->b, stm->c, 0, F->strict, 0));
1365 emitline(J, F, stm);
1366 emit(J, F, OP_SETLOCAL);
1367 emitarg(J, F, addlocal(J, F, stm->a, 1));
1368 emit(J, F, OP_POP);
1369 }
1370 list = list->b;
1371 }
1372 }
1373
1374 static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body, int is_fun_exp)
1375 {
1376 F->lightweight = 1;
1377 F->arguments = 0;
1378
1379 if (F->script)
1380 F->lightweight = 0;
1381
1382 /* Check if first statement is 'use strict': */
1383 if (body && body->type == AST_LIST && body->a && body->a->type == EXP_STRING)
1384 if (!strcmp(body->a->string, "use strict"))
1385 F->strict = 1;
1386
1387 F->lastline = F->line;
1388
1389 cparams(J, F, params, name);
1390
1391 if (body) {
1392 cvardecs(J, F, body);
1393 cfundecs(J, F, body);
1394 }
1395
1396 if (name) {
1397 checkfutureword(J, F, name);
1398 if (is_fun_exp) {
1399 if (findlocal(J, F, name->string) < 0) {
1400 /* TODO: make this binding immutable! */
1401 emit(J, F, OP_CURRENT);
1402 emit(J, F, OP_SETLOCAL);
1403 emitarg(J, F, addlocal(J, F, name, 1));
1404 emit(J, F, OP_POP);
1405 }
1406 }
1407 }
1408
1409 if (F->script) {
1410 emit(J, F, OP_UNDEF);
1411 cstmlist(J, F, body);
1412 emit(J, F, OP_RETURN);
1413 } else {
1414 cstmlist(J, F, body);
1415 emit(J, F, OP_UNDEF);
1416 emit(J, F, OP_RETURN);
1417 }
1418 }
1419
1420 js_Function *jsC_compilefunction(js_State *J, js_Ast *prog)
1421 {
1422 return newfun(J, prog->line, prog->a, prog->b, prog->c, 0, J->default_strict, 1);
1423 }
1424
1425 js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict)
1426 {
1427 return newfun(J, prog ? prog->line : 0, NULL, NULL, prog, 1, default_strict, 0);
1428 }