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