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 | |
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 | |
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 | |
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 | |
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 | |
87 | static void emit(JF, int value) |
88 | { |
89 | emitraw(J, F, F->lastline); |
90 | emitraw(J, F, value); |
91 | } |
92 | |
93 | static void emitarg(JF, int value) |
94 | { |
95 | emitraw(J, F, value); |
96 | } |
97 | |
98 | static void emitline(JF, js_Ast *node) |
99 | { |
100 | F->lastline = node->line; |
101 | } |
102 | |
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 | |
113 | static 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 | |
127 | static 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 | |
141 | static 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 | |
172 | static 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 | |
181 | static 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 | |
188 | static 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 | |
208 | static void emitstring(JF, int opcode, const char *str) |
209 | { |
210 | emit(J, F, opcode); |
211 | emitarg(J, F, addstring(J, F, str)); |
212 | } |
213 | |
214 | static 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 | |
244 | static int here(JF) |
245 | { |
246 | return F->codelen; |
247 | } |
248 | |
249 | static 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 | |
258 | static 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 | |
266 | static 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 | |
273 | static void label(JF, int inst) |
274 | { |
275 | labelto(J, F, inst, F->codelen); |
276 | } |
277 | |
278 | /* Expressions */ |
279 | |
280 | static 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 | |
292 | static 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 | |
299 | static 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 | |
307 | static 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 | |
324 | static 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 | |
348 | static 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 | |
392 | static 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 | |
403 | static 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 | |
431 | static 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 | |
470 | static 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 | |
495 | static 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 | |
518 | static 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 | |
529 | static 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 | |
555 | static 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 | |
566 | static 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 | |
599 | static 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 | |
815 | static 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 | |
824 | static 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 | |
835 | static 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 | |
842 | static 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 | |
847 | static 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 | |
857 | static 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 | |
874 | static 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 | |
890 | static 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 | |
902 | static 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 | |
962 | static 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 | |
977 | static 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 | |
1002 | static 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 | |
1038 | static 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 | |
1083 | static 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 | |
1097 | static 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 | |
1332 | static 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 | |
1342 | static int listlength(js_Ast *list) |
1343 | { |
1344 | int n = 0; |
1345 | while (list) ++n, list = list->b; |
1346 | return n; |
1347 | } |
1348 | |
1349 | static 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 | |
1359 | static 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 | |
1383 | static 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 | |
1399 | static 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 | |
1442 | js_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 | |
1447 | js_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 | |