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