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