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