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
11 JS_NORETURN void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) JS_PRINTFLIKE(3,4);
12
13 static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body);
14 static void cexp(JF, js_Ast *exp);
15 static void cstmlist(JF, js_Ast *list);
16 static void cstm(JF, js_Ast *stm);
17
jsC_error(js_State * J,js_Ast * node,const char * fmt,...)18 void 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
35 static const char *futurewords[] = {
36 "class", "const", "enum", "export", "extends", "import", "super",
37 };
38
39 static const char *strictfuturewords[] = {
40 "implements", "interface", "let", "package", "private", "protected",
41 "public", "static", "yield",
42 };
43
checkfutureword(JF,js_Ast * exp)44 static 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
newfun(js_State * J,int line,js_Ast * name,js_Ast * params,js_Ast * body,int script,int default_strict)54 static 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
emitraw(JF,int value)76 static 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
emit(JF,int value)87 static void emit(JF, int value)
88 {
89 emitraw(J, F, F->lastline);
90 emitraw(J, F, value);
91 }
92
emitarg(JF,int value)93 static void emitarg(JF, int value)
94 {
95 emitraw(J, F, value);
96 }
97
emitline(JF,js_Ast * node)98 static void emitline(JF, js_Ast *node)
99 {
100 F->lastline = node->line;
101 }
102
addfunction(JF,js_Function * value)103 static 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
addlocal(JF,js_Ast * ident,int reuse)113 static int addlocal(JF, js_Ast *ident, int reuse)
114 {
115 const char *name = ident->string;
116 if (F->strict) {
117 if (!strcmp(name, "arguments"))
118 jsC_error(J, ident, "redefining 'arguments' is not allowed in strict mode");
119 if (!strcmp(name, "eval"))
120 jsC_error(J, ident, "redefining 'eval' is not allowed in strict mode");
121 } else {
122 if (!strcmp(name, "eval"))
123 js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line);
124 }
125 if (reuse || F->strict) {
126 int i;
127 for (i = 0; i < F->varlen; ++i) {
128 if (!strcmp(F->vartab[i], name)) {
129 if (reuse)
130 return i+1;
131 if (F->strict)
132 jsC_error(J, ident, "duplicate formal parameter '%s'", name);
133 }
134 }
135 }
136 if (F->varlen >= F->varcap) {
137 F->varcap = F->varcap ? F->varcap * 2 : 16;
138 F->vartab = js_realloc(J, F->vartab, F->varcap * sizeof *F->vartab);
139 }
140 F->vartab[F->varlen] = name;
141 return ++F->varlen;
142 }
143
findlocal(JF,const char * name)144 static int findlocal(JF, const char *name)
145 {
146 int i;
147 for (i = F->varlen; i > 0; --i)
148 if (!strcmp(F->vartab[i-1], name))
149 return i;
150 return -1;
151 }
152
emitfunction(JF,js_Function * fun)153 static void emitfunction(JF, js_Function *fun)
154 {
155 F->lightweight = 0;
156 emit(J, F, OP_CLOSURE);
157 emitarg(J, F, addfunction(J, F, fun));
158 }
159
emitnumber(JF,double num)160 static void emitnumber(JF, double num)
161 {
162 if (num == 0) {
163 emit(J, F, OP_INTEGER);
164 emitarg(J, F, 32768);
165 if (signbit(num))
166 emit(J, F, OP_NEG);
167 } else if (num >= SHRT_MIN && num <= SHRT_MAX && num == (int)num) {
168 emit(J, F, OP_INTEGER);
169 emitarg(J, F, num + 32768);
170 } else {
171 #define N (sizeof(num) / sizeof(js_Instruction))
172 js_Instruction x[N];
173 size_t i;
174 emit(J, F, OP_NUMBER);
175 memcpy(x, &num, sizeof(num));
176 for (i = 0; i < N; ++i)
177 emitarg(J, F, x[i]);
178 #undef N
179 }
180 }
181
emitstring(JF,int opcode,const char * str)182 static void emitstring(JF, int opcode, const char *str)
183 {
184 #define N (sizeof(str) / sizeof(js_Instruction))
185 js_Instruction x[N];
186 size_t i;
187 emit(J, F, opcode);
188 memcpy(x, &str, sizeof(str));
189 for (i = 0; i < N; ++i)
190 emitarg(J, F, x[i]);
191 #undef N
192 }
193
emitlocal(JF,int oploc,int opvar,js_Ast * ident)194 static void emitlocal(JF, int oploc, int opvar, js_Ast *ident)
195 {
196 int is_arguments = !strcmp(ident->string, "arguments");
197 int is_eval = !strcmp(ident->string, "eval");
198 int i;
199
200 if (is_arguments) {
201 F->lightweight = 0;
202 F->arguments = 1;
203 }
204
205 checkfutureword(J, F, ident);
206 if (F->strict && oploc == OP_SETLOCAL) {
207 if (is_arguments)
208 jsC_error(J, ident, "'arguments' is read-only in strict mode");
209 if (is_eval)
210 jsC_error(J, ident, "'eval' is read-only in strict mode");
211 }
212 if (is_eval)
213 js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line);
214
215 i = findlocal(J, F, ident->string);
216 if (i < 0) {
217 emitstring(J, F, opvar, ident->string);
218 } else {
219 emit(J, F, oploc);
220 emitarg(J, F, i);
221 }
222 }
223
here(JF)224 static int here(JF)
225 {
226 return F->codelen;
227 }
228
emitjump(JF,int opcode)229 static int emitjump(JF, int opcode)
230 {
231 int inst;
232 emit(J, F, opcode);
233 inst = F->codelen;
234 emitarg(J, F, 0);
235 return inst;
236 }
237
emitjumpto(JF,int opcode,int dest)238 static void emitjumpto(JF, int opcode, int dest)
239 {
240 emit(J, F, opcode);
241 if (dest != (js_Instruction)dest)
242 js_syntaxerror(J, "jump address integer overflow");
243 emitarg(J, F, dest);
244 }
245
labelto(JF,int inst,int addr)246 static void labelto(JF, int inst, int addr)
247 {
248 if (addr != (js_Instruction)addr)
249 js_syntaxerror(J, "jump address integer overflow");
250 F->code[inst] = addr;
251 }
252
label(JF,int inst)253 static void label(JF, int inst)
254 {
255 labelto(J, F, inst, F->codelen);
256 }
257
258 /* Expressions */
259
ctypeof(JF,js_Ast * exp)260 static void ctypeof(JF, js_Ast *exp)
261 {
262 if (exp->a->type == EXP_IDENTIFIER) {
263 emitline(J, F, exp->a);
264 emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->a);
265 } else {
266 cexp(J, F, exp->a);
267 }
268 emitline(J, F, exp);
269 emit(J, F, OP_TYPEOF);
270 }
271
cunary(JF,js_Ast * exp,int opcode)272 static void cunary(JF, js_Ast *exp, int opcode)
273 {
274 cexp(J, F, exp->a);
275 emitline(J, F, exp);
276 emit(J, F, opcode);
277 }
278
cbinary(JF,js_Ast * exp,int opcode)279 static void cbinary(JF, js_Ast *exp, int opcode)
280 {
281 cexp(J, F, exp->a);
282 cexp(J, F, exp->b);
283 emitline(J, F, exp);
284 emit(J, F, opcode);
285 }
286
carray(JF,js_Ast * list)287 static void carray(JF, js_Ast *list)
288 {
289 while (list) {
290 emitline(J, F, list->a);
291 cexp(J, F, list->a);
292 emit(J, F, OP_INITARRAY);
293 list = list->b;
294 }
295 }
296
checkdup(JF,js_Ast * list,js_Ast * end)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
cobject(JF,js_Ast * list)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));
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));
356 emitline(J, F, kv);
357 emit(J, F, OP_INITSETTER);
358 break;
359 }
360
361 list = list->b;
362 }
363 }
364
cargs(JF,js_Ast * list)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
cassign(JF,js_Ast * exp)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
cassignforin(JF,js_Ast * stm)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
cassignop1(JF,js_Ast * lhs)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
cassignop2(JF,js_Ast * lhs,int postfix)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
cassignop(JF,js_Ast * exp,int opcode)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
cdelete(JF,js_Ast * exp)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
ceval(JF,js_Ast * fun,js_Ast * args)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
ccall(JF,js_Ast * fun,js_Ast * args)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
cexp(JF,js_Ast * exp)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_UNDEF:
588 emitline(J, F, exp);
589 emit(J, F, OP_UNDEF);
590 break;
591 case EXP_NULL:
592 emitline(J, F, exp);
593 emit(J, F, OP_NULL);
594 break;
595 case EXP_TRUE:
596 emitline(J, F, exp);
597 emit(J, F, OP_TRUE);
598 break;
599 case EXP_FALSE:
600 emitline(J, F, exp);
601 emit(J, F, OP_FALSE);
602 break;
603 case EXP_THIS:
604 emitline(J, F, exp);
605 emit(J, F, OP_THIS);
606 break;
607
608 case EXP_REGEXP:
609 emitline(J, F, exp);
610 emitstring(J, F, OP_NEWREGEXP, exp->string);
611 emitarg(J, F, exp->number);
612 break;
613
614 case EXP_OBJECT:
615 emitline(J, F, exp);
616 emit(J, F, OP_NEWOBJECT);
617 cobject(J, F, exp->a);
618 break;
619
620 case EXP_ARRAY:
621 emitline(J, F, exp);
622 emit(J, F, OP_NEWARRAY);
623 carray(J, F, exp->a);
624 break;
625
626 case EXP_FUN:
627 emitline(J, F, exp);
628 emitfunction(J, F, newfun(J, exp->line, exp->a, exp->b, exp->c, 0, F->strict));
629 break;
630
631 case EXP_IDENTIFIER:
632 emitline(J, F, exp);
633 emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp);
634 break;
635
636 case EXP_INDEX:
637 cexp(J, F, exp->a);
638 cexp(J, F, exp->b);
639 emitline(J, F, exp);
640 emit(J, F, OP_GETPROP);
641 break;
642
643 case EXP_MEMBER:
644 cexp(J, F, exp->a);
645 emitline(J, F, exp);
646 emitstring(J, F, OP_GETPROP_S, exp->b->string);
647 break;
648
649 case EXP_CALL:
650 ccall(J, F, exp->a, exp->b);
651 break;
652
653 case EXP_NEW:
654 cexp(J, F, exp->a);
655 n = cargs(J, F, exp->b);
656 emitline(J, F, exp);
657 emit(J, F, OP_NEW);
658 emitarg(J, F, n);
659 break;
660
661 case EXP_DELETE:
662 cdelete(J, F, exp);
663 break;
664
665 case EXP_PREINC:
666 cassignop1(J, F, exp->a);
667 emitline(J, F, exp);
668 emit(J, F, OP_INC);
669 cassignop2(J, F, exp->a, 0);
670 break;
671
672 case EXP_PREDEC:
673 cassignop1(J, F, exp->a);
674 emitline(J, F, exp);
675 emit(J, F, OP_DEC);
676 cassignop2(J, F, exp->a, 0);
677 break;
678
679 case EXP_POSTINC:
680 cassignop1(J, F, exp->a);
681 emitline(J, F, exp);
682 emit(J, F, OP_POSTINC);
683 cassignop2(J, F, exp->a, 1);
684 emit(J, F, OP_POP);
685 break;
686
687 case EXP_POSTDEC:
688 cassignop1(J, F, exp->a);
689 emitline(J, F, exp);
690 emit(J, F, OP_POSTDEC);
691 cassignop2(J, F, exp->a, 1);
692 emit(J, F, OP_POP);
693 break;
694
695 case EXP_VOID:
696 cexp(J, F, exp->a);
697 emitline(J, F, exp);
698 emit(J, F, OP_POP);
699 emit(J, F, OP_UNDEF);
700 break;
701
702 case EXP_TYPEOF: ctypeof(J, F, exp); break;
703 case EXP_POS: cunary(J, F, exp, OP_POS); break;
704 case EXP_NEG: cunary(J, F, exp, OP_NEG); break;
705 case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break;
706 case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break;
707
708 case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break;
709 case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break;
710 case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break;
711 case EXP_EQ: cbinary(J, F, exp, OP_EQ); break;
712 case EXP_NE: cbinary(J, F, exp, OP_NE); break;
713 case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break;
714 case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break;
715 case EXP_LT: cbinary(J, F, exp, OP_LT); break;
716 case EXP_GT: cbinary(J, F, exp, OP_GT); break;
717 case EXP_LE: cbinary(J, F, exp, OP_LE); break;
718 case EXP_GE: cbinary(J, F, exp, OP_GE); break;
719 case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break;
720 case EXP_IN: cbinary(J, F, exp, OP_IN); break;
721 case EXP_SHL: cbinary(J, F, exp, OP_SHL); break;
722 case EXP_SHR: cbinary(J, F, exp, OP_SHR); break;
723 case EXP_USHR: cbinary(J, F, exp, OP_USHR); break;
724 case EXP_ADD: cbinary(J, F, exp, OP_ADD); break;
725 case EXP_SUB: cbinary(J, F, exp, OP_SUB); break;
726 case EXP_MUL: cbinary(J, F, exp, OP_MUL); break;
727 case EXP_DIV: cbinary(J, F, exp, OP_DIV); break;
728 case EXP_MOD: cbinary(J, F, exp, OP_MOD); break;
729
730 case EXP_ASS: cassign(J, F, exp); break;
731 case EXP_ASS_MUL: cassignop(J, F, exp, OP_MUL); break;
732 case EXP_ASS_DIV: cassignop(J, F, exp, OP_DIV); break;
733 case EXP_ASS_MOD: cassignop(J, F, exp, OP_MOD); break;
734 case EXP_ASS_ADD: cassignop(J, F, exp, OP_ADD); break;
735 case EXP_ASS_SUB: cassignop(J, F, exp, OP_SUB); break;
736 case EXP_ASS_SHL: cassignop(J, F, exp, OP_SHL); break;
737 case EXP_ASS_SHR: cassignop(J, F, exp, OP_SHR); break;
738 case EXP_ASS_USHR: cassignop(J, F, exp, OP_USHR); break;
739 case EXP_ASS_BITAND: cassignop(J, F, exp, OP_BITAND); break;
740 case EXP_ASS_BITXOR: cassignop(J, F, exp, OP_BITXOR); break;
741 case EXP_ASS_BITOR: cassignop(J, F, exp, OP_BITOR); break;
742
743 case EXP_COMMA:
744 cexp(J, F, exp->a);
745 emitline(J, F, exp);
746 emit(J, F, OP_POP);
747 cexp(J, F, exp->b);
748 break;
749
750 case EXP_LOGOR:
751 cexp(J, F, exp->a);
752 emitline(J, F, exp);
753 emit(J, F, OP_DUP);
754 end = emitjump(J, F, OP_JTRUE);
755 emit(J, F, OP_POP);
756 cexp(J, F, exp->b);
757 label(J, F, end);
758 break;
759
760 case EXP_LOGAND:
761 cexp(J, F, exp->a);
762 emitline(J, F, exp);
763 emit(J, F, OP_DUP);
764 end = emitjump(J, F, OP_JFALSE);
765 emit(J, F, OP_POP);
766 cexp(J, F, exp->b);
767 label(J, F, end);
768 break;
769
770 case EXP_COND:
771 cexp(J, F, exp->a);
772 emitline(J, F, exp);
773 then = emitjump(J, F, OP_JTRUE);
774 cexp(J, F, exp->c);
775 end = emitjump(J, F, OP_JUMP);
776 label(J, F, then);
777 cexp(J, F, exp->b);
778 label(J, F, end);
779 break;
780
781 default:
782 jsC_error(J, exp, "unknown expression: (%s)", jsP_aststring(exp->type));
783 }
784 }
785
786 /* Patch break and continue statements */
787
addjump(JF,enum js_AstType type,js_Ast * target,int inst)788 static void addjump(JF, enum js_AstType type, js_Ast *target, int inst)
789 {
790 js_JumpList *jump = js_malloc(J, sizeof *jump);
791 jump->type = type;
792 jump->inst = inst;
793 jump->next = target->jumps;
794 target->jumps = jump;
795 }
796
labeljumps(JF,js_Ast * stm,int baddr,int caddr)797 static void labeljumps(JF, js_Ast *stm, int baddr, int caddr)
798 {
799 js_JumpList *jump = stm->jumps;
800 while (jump) {
801 js_JumpList *next = jump->next;
802 if (jump->type == STM_BREAK)
803 labelto(J, F, jump->inst, baddr);
804 if (jump->type == STM_CONTINUE)
805 labelto(J, F, jump->inst, caddr);
806 js_free(J, jump);
807 jump = next;
808 }
809 stm->jumps = NULL;
810 }
811
isloop(enum js_AstType T)812 static int isloop(enum js_AstType T)
813 {
814 return T == STM_DO || T == STM_WHILE ||
815 T == STM_FOR || T == STM_FOR_VAR ||
816 T == STM_FOR_IN || T == STM_FOR_IN_VAR;
817 }
818
isfun(enum js_AstType T)819 static int isfun(enum js_AstType T)
820 {
821 return T == AST_FUNDEC || T == EXP_FUN || T == EXP_PROP_GET || T == EXP_PROP_SET;
822 }
823
matchlabel(js_Ast * node,const char * label)824 static int matchlabel(js_Ast *node, const char *label)
825 {
826 while (node && node->type == STM_LABEL) {
827 if (!strcmp(node->a->string, label))
828 return 1;
829 node = node->parent;
830 }
831 return 0;
832 }
833
breaktarget(JF,js_Ast * node,const char * label)834 static js_Ast *breaktarget(JF, js_Ast *node, const char *label)
835 {
836 while (node) {
837 if (isfun(node->type))
838 break;
839 if (!label) {
840 if (isloop(node->type) || node->type == STM_SWITCH)
841 return node;
842 } else {
843 if (matchlabel(node->parent, label))
844 return node;
845 }
846 node = node->parent;
847 }
848 return NULL;
849 }
850
continuetarget(JF,js_Ast * node,const char * label)851 static js_Ast *continuetarget(JF, js_Ast *node, const char *label)
852 {
853 while (node) {
854 if (isfun(node->type))
855 break;
856 if (isloop(node->type)) {
857 if (!label)
858 return node;
859 else if (matchlabel(node->parent, label))
860 return node;
861 }
862 node = node->parent;
863 }
864 return NULL;
865 }
866
returntarget(JF,js_Ast * node)867 static js_Ast *returntarget(JF, js_Ast *node)
868 {
869 while (node) {
870 if (isfun(node->type))
871 return node;
872 node = node->parent;
873 }
874 return NULL;
875 }
876
877 /* Emit code to rebalance stack and scopes during an abrupt exit */
878
cexit(JF,enum js_AstType T,js_Ast * node,js_Ast * target)879 static void cexit(JF, enum js_AstType T, js_Ast *node, js_Ast *target)
880 {
881 js_Ast *prev;
882 do {
883 prev = node, node = node->parent;
884 switch (node->type) {
885 default:
886 /* impossible */
887 break;
888 case STM_WITH:
889 emitline(J, F, node);
890 emit(J, F, OP_ENDWITH);
891 break;
892 case STM_FOR_IN:
893 case STM_FOR_IN_VAR:
894 emitline(J, F, node);
895 /* pop the iterator if leaving the loop */
896 if (F->script) {
897 if (T == STM_RETURN || T == STM_BREAK || (T == STM_CONTINUE && target != node)) {
898 /* pop the iterator, save the return or exp value */
899 emit(J, F, OP_ROT2);
900 emit(J, F, OP_POP);
901 }
902 if (T == STM_CONTINUE)
903 emit(J, F, OP_ROT2); /* put the iterator back on top */
904 } else {
905 if (T == STM_RETURN) {
906 /* pop the iterator, save the return value */
907 emit(J, F, OP_ROT2);
908 emit(J, F, OP_POP);
909 }
910 if (T == STM_BREAK || (T == STM_CONTINUE && target != node))
911 emit(J, F, OP_POP); /* pop the iterator */
912 }
913 break;
914 case STM_TRY:
915 emitline(J, F, node);
916 /* came from try block */
917 if (prev == node->a) {
918 emit(J, F, OP_ENDTRY);
919 if (node->d) cstm(J, F, node->d); /* finally */
920 }
921 /* came from catch block */
922 if (prev == node->c) {
923 /* ... with finally */
924 if (node->d) {
925 emit(J, F, OP_ENDCATCH);
926 emit(J, F, OP_ENDTRY);
927 cstm(J, F, node->d); /* finally */
928 } else {
929 emit(J, F, OP_ENDCATCH);
930 }
931 }
932 break;
933 }
934 } while (node != target);
935 }
936
937 /* Try/catch/finally */
938
ctryfinally(JF,js_Ast * trystm,js_Ast * finallystm)939 static void ctryfinally(JF, js_Ast *trystm, js_Ast *finallystm)
940 {
941 int L1;
942 L1 = emitjump(J, F, OP_TRY);
943 {
944 /* if we get here, we have caught an exception in the try block */
945 cstm(J, F, finallystm); /* inline finally block */
946 emit(J, F, OP_THROW); /* rethrow exception */
947 }
948 label(J, F, L1);
949 cstm(J, F, trystm);
950 emit(J, F, OP_ENDTRY);
951 cstm(J, F, finallystm);
952 }
953
ctrycatch(JF,js_Ast * trystm,js_Ast * catchvar,js_Ast * catchstm)954 static void ctrycatch(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm)
955 {
956 int L1, L2;
957 L1 = emitjump(J, F, OP_TRY);
958 {
959 /* if we get here, we have caught an exception in the try block */
960 checkfutureword(J, F, catchvar);
961 if (F->strict) {
962 if (!strcmp(catchvar->string, "arguments"))
963 jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode");
964 if (!strcmp(catchvar->string, "eval"))
965 jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode");
966 }
967 emitline(J, F, catchvar);
968 emitstring(J, F, OP_CATCH, catchvar->string);
969 cstm(J, F, catchstm);
970 emit(J, F, OP_ENDCATCH);
971 L2 = emitjump(J, F, OP_JUMP); /* skip past the try block */
972 }
973 label(J, F, L1);
974 cstm(J, F, trystm);
975 emit(J, F, OP_ENDTRY);
976 label(J, F, L2);
977 }
978
ctrycatchfinally(JF,js_Ast * trystm,js_Ast * catchvar,js_Ast * catchstm,js_Ast * finallystm)979 static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm)
980 {
981 int L1, L2, L3;
982 L1 = emitjump(J, F, OP_TRY);
983 {
984 /* if we get here, we have caught an exception in the try block */
985 L2 = emitjump(J, F, OP_TRY);
986 {
987 /* if we get here, we have caught an exception in the catch block */
988 cstm(J, F, finallystm); /* inline finally block */
989 emit(J, F, OP_THROW); /* rethrow exception */
990 }
991 label(J, F, L2);
992 if (F->strict) {
993 checkfutureword(J, F, catchvar);
994 if (!strcmp(catchvar->string, "arguments"))
995 jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode");
996 if (!strcmp(catchvar->string, "eval"))
997 jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode");
998 }
999 emitline(J, F, catchvar);
1000 emitstring(J, F, OP_CATCH, catchvar->string);
1001 cstm(J, F, catchstm);
1002 emit(J, F, OP_ENDCATCH);
1003 emit(J, F, OP_ENDTRY);
1004 L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */
1005 }
1006 label(J, F, L1);
1007 cstm(J, F, trystm);
1008 emit(J, F, OP_ENDTRY);
1009 label(J, F, L3);
1010 cstm(J, F, finallystm);
1011 }
1012
1013 /* Switch */
1014
cswitch(JF,js_Ast * ref,js_Ast * head)1015 static void cswitch(JF, js_Ast *ref, js_Ast *head)
1016 {
1017 js_Ast *node, *clause, *def = NULL;
1018 int end;
1019
1020 cexp(J, F, ref);
1021
1022 /* emit an if-else chain of tests for the case clause expressions */
1023 for (node = head; node; node = node->b) {
1024 clause = node->a;
1025 if (clause->type == STM_DEFAULT) {
1026 if (def)
1027 jsC_error(J, clause, "more than one default label in switch");
1028 def = clause;
1029 } else {
1030 cexp(J, F, clause->a);
1031 emitline(J, F, clause);
1032 clause->casejump = emitjump(J, F, OP_JCASE);
1033 }
1034 }
1035 emit(J, F, OP_POP);
1036 if (def) {
1037 emitline(J, F, def);
1038 def->casejump = emitjump(J, F, OP_JUMP);
1039 end = 0;
1040 } else {
1041 end = emitjump(J, F, OP_JUMP);
1042 }
1043
1044 /* emit the case clause bodies */
1045 for (node = head; node; node = node->b) {
1046 clause = node->a;
1047 label(J, F, clause->casejump);
1048 if (clause->type == STM_DEFAULT)
1049 cstmlist(J, F, clause->a);
1050 else
1051 cstmlist(J, F, clause->b);
1052 }
1053
1054 if (end)
1055 label(J, F, end);
1056 }
1057
1058 /* Statements */
1059
cvarinit(JF,js_Ast * list)1060 static void cvarinit(JF, js_Ast *list)
1061 {
1062 while (list) {
1063 js_Ast *var = list->a;
1064 if (var->b) {
1065 cexp(J, F, var->b);
1066 emitline(J, F, var);
1067 emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, var->a);
1068 emit(J, F, OP_POP);
1069 }
1070 list = list->b;
1071 }
1072 }
1073
cstm(JF,js_Ast * stm)1074 static void cstm(JF, js_Ast *stm)
1075 {
1076 js_Ast *target;
1077 int loop, cont, then, end;
1078
1079 emitline(J, F, stm);
1080
1081 switch (stm->type) {
1082 case AST_FUNDEC:
1083 break;
1084
1085 case STM_BLOCK:
1086 cstmlist(J, F, stm->a);
1087 break;
1088
1089 case STM_EMPTY:
1090 if (F->script) {
1091 emitline(J, F, stm);
1092 emit(J, F, OP_POP);
1093 emit(J, F, OP_UNDEF);
1094 }
1095 break;
1096
1097 case STM_VAR:
1098 cvarinit(J, F, stm->a);
1099 break;
1100
1101 case STM_IF:
1102 if (stm->c) {
1103 cexp(J, F, stm->a);
1104 emitline(J, F, stm);
1105 then = emitjump(J, F, OP_JTRUE);
1106 cstm(J, F, stm->c);
1107 emitline(J, F, stm);
1108 end = emitjump(J, F, OP_JUMP);
1109 label(J, F, then);
1110 cstm(J, F, stm->b);
1111 label(J, F, end);
1112 } else {
1113 cexp(J, F, stm->a);
1114 emitline(J, F, stm);
1115 end = emitjump(J, F, OP_JFALSE);
1116 cstm(J, F, stm->b);
1117 label(J, F, end);
1118 }
1119 break;
1120
1121 case STM_DO:
1122 loop = here(J, F);
1123 cstm(J, F, stm->a);
1124 cont = here(J, F);
1125 cexp(J, F, stm->b);
1126 emitline(J, F, stm);
1127 emitjumpto(J, F, OP_JTRUE, loop);
1128 labeljumps(J, F, stm, here(J,F), cont);
1129 break;
1130
1131 case STM_WHILE:
1132 loop = here(J, F);
1133 cexp(J, F, stm->a);
1134 emitline(J, F, stm);
1135 end = emitjump(J, F, OP_JFALSE);
1136 cstm(J, F, stm->b);
1137 emitline(J, F, stm);
1138 emitjumpto(J, F, OP_JUMP, loop);
1139 label(J, F, end);
1140 labeljumps(J, F, stm, here(J,F), loop);
1141 break;
1142
1143 case STM_FOR:
1144 case STM_FOR_VAR:
1145 if (stm->type == STM_FOR_VAR) {
1146 cvarinit(J, F, stm->a);
1147 } else {
1148 if (stm->a) {
1149 cexp(J, F, stm->a);
1150 emit(J, F, OP_POP);
1151 }
1152 }
1153 loop = here(J, F);
1154 if (stm->b) {
1155 cexp(J, F, stm->b);
1156 emitline(J, F, stm);
1157 end = emitjump(J, F, OP_JFALSE);
1158 } else {
1159 end = 0;
1160 }
1161 cstm(J, F, stm->d);
1162 cont = here(J, F);
1163 if (stm->c) {
1164 cexp(J, F, stm->c);
1165 emit(J, F, OP_POP);
1166 }
1167 emitline(J, F, stm);
1168 emitjumpto(J, F, OP_JUMP, loop);
1169 if (end)
1170 label(J, F, end);
1171 labeljumps(J, F, stm, here(J,F), cont);
1172 break;
1173
1174 case STM_FOR_IN:
1175 case STM_FOR_IN_VAR:
1176 cexp(J, F, stm->b);
1177 emitline(J, F, stm);
1178 emit(J, F, OP_ITERATOR);
1179 loop = here(J, F);
1180 {
1181 emitline(J, F, stm);
1182 emit(J, F, OP_NEXTITER);
1183 end = emitjump(J, F, OP_JFALSE);
1184 cassignforin(J, F, stm);
1185 if (F->script) {
1186 emit(J, F, OP_ROT2);
1187 cstm(J, F, stm->c);
1188 emit(J, F, OP_ROT2);
1189 } else {
1190 cstm(J, F, stm->c);
1191 }
1192 emitline(J, F, stm);
1193 emitjumpto(J, F, OP_JUMP, loop);
1194 }
1195 label(J, F, end);
1196 labeljumps(J, F, stm, here(J,F), loop);
1197 break;
1198
1199 case STM_SWITCH:
1200 cswitch(J, F, stm->a, stm->b);
1201 labeljumps(J, F, stm, here(J,F), 0);
1202 break;
1203
1204 case STM_LABEL:
1205 cstm(J, F, stm->b);
1206 /* skip consecutive labels */
1207 while (stm->type == STM_LABEL)
1208 stm = stm->b;
1209 /* loops and switches have already been labelled */
1210 if (!isloop(stm->type) && stm->type != STM_SWITCH)
1211 labeljumps(J, F, stm, here(J,F), 0);
1212 break;
1213
1214 case STM_BREAK:
1215 if (stm->a) {
1216 checkfutureword(J, F, stm->a);
1217 target = breaktarget(J, F, stm->parent, stm->a->string);
1218 if (!target)
1219 jsC_error(J, stm, "break label '%s' not found", stm->a->string);
1220 } else {
1221 target = breaktarget(J, F, stm->parent, NULL);
1222 if (!target)
1223 jsC_error(J, stm, "unlabelled break must be inside loop or switch");
1224 }
1225 cexit(J, F, STM_BREAK, stm, target);
1226 emitline(J, F, stm);
1227 addjump(J, F, STM_BREAK, target, emitjump(J, F, OP_JUMP));
1228 break;
1229
1230 case STM_CONTINUE:
1231 if (stm->a) {
1232 checkfutureword(J, F, stm->a);
1233 target = continuetarget(J, F, stm->parent, stm->a->string);
1234 if (!target)
1235 jsC_error(J, stm, "continue label '%s' not found", stm->a->string);
1236 } else {
1237 target = continuetarget(J, F, stm->parent, NULL);
1238 if (!target)
1239 jsC_error(J, stm, "continue must be inside loop");
1240 }
1241 cexit(J, F, STM_CONTINUE, stm, target);
1242 emitline(J, F, stm);
1243 addjump(J, F, STM_CONTINUE, target, emitjump(J, F, OP_JUMP));
1244 break;
1245
1246 case STM_RETURN:
1247 if (stm->a)
1248 cexp(J, F, stm->a);
1249 else
1250 emit(J, F, OP_UNDEF);
1251 target = returntarget(J, F, stm->parent);
1252 if (!target)
1253 jsC_error(J, stm, "return not in function");
1254 cexit(J, F, STM_RETURN, stm, target);
1255 emitline(J, F, stm);
1256 emit(J, F, OP_RETURN);
1257 break;
1258
1259 case STM_THROW:
1260 cexp(J, F, stm->a);
1261 emitline(J, F, stm);
1262 emit(J, F, OP_THROW);
1263 break;
1264
1265 case STM_WITH:
1266 F->lightweight = 0;
1267 if (F->strict)
1268 jsC_error(J, stm->a, "'with' statements are not allowed in strict mode");
1269 cexp(J, F, stm->a);
1270 emitline(J, F, stm);
1271 emit(J, F, OP_WITH);
1272 cstm(J, F, stm->b);
1273 emitline(J, F, stm);
1274 emit(J, F, OP_ENDWITH);
1275 break;
1276
1277 case STM_TRY:
1278 emitline(J, F, stm);
1279 if (stm->b && stm->c) {
1280 F->lightweight = 0;
1281 if (stm->d)
1282 ctrycatchfinally(J, F, stm->a, stm->b, stm->c, stm->d);
1283 else
1284 ctrycatch(J, F, stm->a, stm->b, stm->c);
1285 } else {
1286 ctryfinally(J, F, stm->a, stm->d);
1287 }
1288 break;
1289
1290 case STM_DEBUGGER:
1291 emitline(J, F, stm);
1292 emit(J, F, OP_DEBUGGER);
1293 break;
1294
1295 default:
1296 if (F->script) {
1297 emitline(J, F, stm);
1298 emit(J, F, OP_POP);
1299 cexp(J, F, stm);
1300 } else {
1301 cexp(J, F, stm);
1302 emitline(J, F, stm);
1303 emit(J, F, OP_POP);
1304 }
1305 break;
1306 }
1307 }
1308
cstmlist(JF,js_Ast * list)1309 static void cstmlist(JF, js_Ast *list)
1310 {
1311 while (list) {
1312 cstm(J, F, list->a);
1313 list = list->b;
1314 }
1315 }
1316
1317 /* Declarations and programs */
1318
listlength(js_Ast * list)1319 static int listlength(js_Ast *list)
1320 {
1321 int n = 0;
1322 while (list) ++n, list = list->b;
1323 return n;
1324 }
1325
cparams(JF,js_Ast * list,js_Ast * fname)1326 static void cparams(JF, js_Ast *list, js_Ast *fname)
1327 {
1328 F->numparams = listlength(list);
1329 while (list) {
1330 checkfutureword(J, F, list->a);
1331 addlocal(J, F, list->a, 0);
1332 list = list->b;
1333 }
1334 }
1335
cvardecs(JF,js_Ast * node)1336 static void cvardecs(JF, js_Ast *node)
1337 {
1338 if (node->type == AST_LIST) {
1339 while (node) {
1340 cvardecs(J, F, node->a);
1341 node = node->b;
1342 }
1343 return;
1344 }
1345
1346 if (isfun(node->type))
1347 return; /* stop at inner functions */
1348
1349 if (node->type == EXP_VAR) {
1350 checkfutureword(J, F, node->a);
1351 addlocal(J, F, node->a, 1);
1352 }
1353
1354 if (node->a) cvardecs(J, F, node->a);
1355 if (node->b) cvardecs(J, F, node->b);
1356 if (node->c) cvardecs(J, F, node->c);
1357 if (node->d) cvardecs(J, F, node->d);
1358 }
1359
cfundecs(JF,js_Ast * list)1360 static void cfundecs(JF, js_Ast *list)
1361 {
1362 while (list) {
1363 js_Ast *stm = list->a;
1364 if (stm->type == AST_FUNDEC) {
1365 emitline(J, F, stm);
1366 emitfunction(J, F, newfun(J, stm->line, stm->a, stm->b, stm->c, 0, F->strict));
1367 emitline(J, F, stm);
1368 emit(J, F, OP_SETLOCAL);
1369 emitarg(J, F, addlocal(J, F, stm->a, 0));
1370 emit(J, F, OP_POP);
1371 }
1372 list = list->b;
1373 }
1374 }
1375
cfunbody(JF,js_Ast * name,js_Ast * params,js_Ast * body)1376 static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body)
1377 {
1378 F->lightweight = 1;
1379 F->arguments = 0;
1380
1381 if (F->script)
1382 F->lightweight = 0;
1383
1384 /* Check if first statement is 'use strict': */
1385 if (body && body->type == AST_LIST && body->a && body->a->type == EXP_STRING)
1386 if (!strcmp(body->a->string, "use strict"))
1387 F->strict = 1;
1388
1389 F->lastline = F->line;
1390
1391 cparams(J, F, params, name);
1392
1393 if (body) {
1394 cvardecs(J, F, body);
1395 cfundecs(J, F, body);
1396 }
1397
1398 if (name) {
1399 checkfutureword(J, F, name);
1400 if (findlocal(J, F, name->string) < 0) {
1401 emit(J, F, OP_CURRENT);
1402 emit(J, F, OP_SETLOCAL);
1403 emitarg(J, F, addlocal(J, F, name, 0));
1404 emit(J, F, OP_POP);
1405 }
1406 }
1407
1408 if (F->script) {
1409 emit(J, F, OP_UNDEF);
1410 cstmlist(J, F, body);
1411 emit(J, F, OP_RETURN);
1412 } else {
1413 cstmlist(J, F, body);
1414 emit(J, F, OP_UNDEF);
1415 emit(J, F, OP_RETURN);
1416 }
1417 }
1418
jsC_compilefunction(js_State * J,js_Ast * prog)1419 js_Function *jsC_compilefunction(js_State *J, js_Ast *prog)
1420 {
1421 return newfun(J, prog->line, prog->a, prog->b, prog->c, 0, J->default_strict);
1422 }
1423
jsC_compilescript(js_State * J,js_Ast * prog,int default_strict)1424 js_Function *jsC_compilescript(js_State *J, js_Ast *prog, int default_strict)
1425 {
1426 return newfun(J, prog ? prog->line : 0, NULL, NULL, prog, 1, default_strict);
1427 }
1428