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