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