Coverage Report

Created: 2024-05-20 06:23

/src/mupdf/thirdparty/mujs/jsparse.c
Line
Count
Source (jump to first uncovered line)
1
#include "jsi.h"
2
3
0
#define LIST(h)     jsP_newnode(J, AST_LIST, 0, h, 0, 0, 0)
4
5
0
#define EXP0(x)     jsP_newnode(J, EXP_ ## x, line, 0, 0, 0, 0)
6
0
#define EXP1(x,a)   jsP_newnode(J, EXP_ ## x, line, a, 0, 0, 0)
7
0
#define EXP2(x,a,b)   jsP_newnode(J, EXP_ ## x, line, a, b, 0, 0)
8
0
#define EXP3(x,a,b,c)   jsP_newnode(J, EXP_ ## x, line, a, b, c, 0)
9
10
0
#define STM0(x)     jsP_newnode(J, STM_ ## x, line, 0, 0, 0, 0)
11
0
#define STM1(x,a)   jsP_newnode(J, STM_ ## x, line, a, 0, 0, 0)
12
0
#define STM2(x,a,b)   jsP_newnode(J, STM_ ## x, line, a, b, 0, 0)
13
0
#define STM3(x,a,b,c)   jsP_newnode(J, STM_ ## x, line, a, b, c, 0)
14
0
#define STM4(x,a,b,c,d)   jsP_newnode(J, STM_ ## x, line, a, b, c, d)
15
16
static js_Ast *expression(js_State *J, int notin);
17
static js_Ast *assignment(js_State *J, int notin);
18
static js_Ast *memberexp(js_State *J);
19
static js_Ast *statement(js_State *J);
20
static js_Ast *funbody(js_State *J);
21
22
JS_NORETURN static void jsP_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3);
23
24
0
#define INCREC() if (++J->astdepth > JS_ASTLIMIT) jsP_error(J, "too much recursion")
25
0
#define DECREC() --J->astdepth
26
0
#define SAVEREC() int SAVE=J->astdepth
27
0
#define POPREC() J->astdepth=SAVE
28
29
static void jsP_error(js_State *J, const char *fmt, ...)
30
0
{
31
0
  va_list ap;
32
0
  char buf[512];
33
0
  char msgbuf[256];
34
35
0
  va_start(ap, fmt);
36
0
  vsnprintf(msgbuf, 256, fmt, ap);
37
0
  va_end(ap);
38
39
0
  snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline);
40
0
  strcat(buf, msgbuf);
41
42
0
  js_newsyntaxerror(J, buf);
43
0
  js_throw(J);
44
0
}
45
46
static void jsP_warning(js_State *J, const char *fmt, ...)
47
0
{
48
0
  va_list ap;
49
0
  char buf[512];
50
0
  char msg[256];
51
52
0
  va_start(ap, fmt);
53
0
  vsnprintf(msg, sizeof msg, fmt, ap);
54
0
  va_end(ap);
55
56
0
  snprintf(buf, sizeof buf, "%s:%d: warning: %s", J->filename, J->lexline, msg);
57
0
  js_report(J, buf);
58
0
}
59
60
static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, int line, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d)
61
0
{
62
0
  js_Ast *node = js_malloc(J, sizeof *node);
63
64
0
  node->type = type;
65
0
  node->line = line;
66
0
  node->a = a;
67
0
  node->b = b;
68
0
  node->c = c;
69
0
  node->d = d;
70
0
  node->number = 0;
71
0
  node->string = NULL;
72
0
  node->jumps = NULL;
73
0
  node->casejump = 0;
74
75
0
  node->parent = NULL;
76
0
  if (a) a->parent = node;
77
0
  if (b) b->parent = node;
78
0
  if (c) c->parent = node;
79
0
  if (d) d->parent = node;
80
81
0
  node->gcnext = J->gcast;
82
0
  J->gcast = node;
83
84
0
  return node;
85
0
}
86
87
static js_Ast *jsP_list(js_Ast *head)
88
0
{
89
  /* set parent pointers in list nodes */
90
0
  js_Ast *prev = head, *node = head->b;
91
0
  while (node) {
92
0
    node->parent = prev;
93
0
    prev = node;
94
0
    node = node->b;
95
0
  }
96
0
  return head;
97
0
}
98
99
static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s)
100
0
{
101
0
  js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0);
102
0
  node->string = s;
103
0
  return node;
104
0
}
105
106
static js_Ast *jsP_newnumnode(js_State *J, enum js_AstType type, double n)
107
0
{
108
0
  js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0);
109
0
  node->number = n;
110
0
  return node;
111
0
}
112
113
static void jsP_freejumps(js_State *J, js_JumpList *node)
114
0
{
115
0
  while (node) {
116
0
    js_JumpList *next = node->next;
117
0
    js_free(J, node);
118
0
    node = next;
119
0
  }
120
0
}
121
122
void jsP_freeparse(js_State *J)
123
0
{
124
0
  js_Ast *node = J->gcast;
125
0
  while (node) {
126
0
    js_Ast *next = node->gcnext;
127
0
    jsP_freejumps(J, node->jumps);
128
0
    js_free(J, node);
129
0
    node = next;
130
0
  }
131
0
  J->gcast = NULL;
132
0
}
133
134
/* Lookahead */
135
136
static void jsP_next(js_State *J)
137
0
{
138
0
  J->lookahead = jsY_lex(J);
139
0
}
140
141
0
#define jsP_accept(J,x) (J->lookahead == x ? (jsP_next(J), 1) : 0)
142
143
0
#define jsP_expect(J,x) if (!jsP_accept(J, x)) jsP_error(J, "unexpected token: %s (expected %s)", jsY_tokenstring(J->lookahead), jsY_tokenstring(x))
144
145
static void semicolon(js_State *J)
146
0
{
147
0
  if (J->lookahead == ';') {
148
0
    jsP_next(J);
149
0
    return;
150
0
  }
151
0
  if (J->newline || J->lookahead == '}' || J->lookahead == 0)
152
0
    return;
153
0
  jsP_error(J, "unexpected token: %s (expected ';')", jsY_tokenstring(J->lookahead));
154
0
}
155
156
/* Literals */
157
158
static js_Ast *identifier(js_State *J)
159
0
{
160
0
  js_Ast *a;
161
0
  if (J->lookahead == TK_IDENTIFIER) {
162
0
    a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
163
0
    jsP_next(J);
164
0
    return a;
165
0
  }
166
0
  jsP_error(J, "unexpected token: %s (expected identifier)", jsY_tokenstring(J->lookahead));
167
0
}
168
169
static js_Ast *identifieropt(js_State *J)
170
0
{
171
0
  if (J->lookahead == TK_IDENTIFIER)
172
0
    return identifier(J);
173
0
  return NULL;
174
0
}
175
176
static js_Ast *identifiername(js_State *J)
177
0
{
178
0
  if (J->lookahead == TK_IDENTIFIER || J->lookahead >= TK_BREAK) {
179
0
    js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text);
180
0
    jsP_next(J);
181
0
    return a;
182
0
  }
183
0
  jsP_error(J, "unexpected token: %s (expected identifier or keyword)", jsY_tokenstring(J->lookahead));
184
0
}
185
186
static js_Ast *arrayelement(js_State *J)
187
0
{
188
0
  int line = J->lexline;
189
0
  if (J->lookahead == ',')
190
0
    return EXP0(ELISION);
191
0
  return assignment(J, 0);
192
0
}
193
194
static js_Ast *arrayliteral(js_State *J)
195
0
{
196
0
  js_Ast *head, *tail;
197
0
  if (J->lookahead == ']')
198
0
    return NULL;
199
0
  head = tail = LIST(arrayelement(J));
200
0
  while (jsP_accept(J, ',')) {
201
0
    if (J->lookahead != ']')
202
0
      tail = tail->b = LIST(arrayelement(J));
203
0
  }
204
0
  return jsP_list(head);
205
0
}
206
207
static js_Ast *propname(js_State *J)
208
0
{
209
0
  js_Ast *name;
210
0
  if (J->lookahead == TK_NUMBER) {
211
0
    name = jsP_newnumnode(J, EXP_NUMBER, J->number);
212
0
    jsP_next(J);
213
0
  } else if (J->lookahead == TK_STRING) {
214
0
    name = jsP_newstrnode(J, EXP_STRING, J->text);
215
0
    jsP_next(J);
216
0
  } else {
217
0
    name = identifiername(J);
218
0
  }
219
0
  return name;
220
0
}
221
222
static js_Ast *propassign(js_State *J)
223
0
{
224
0
  js_Ast *name, *value, *arg, *body;
225
0
  int line = J->lexline;
226
227
0
  name = propname(J);
228
229
0
  if (J->lookahead != ':' && name->type == AST_IDENTIFIER) {
230
0
    if (!strcmp(name->string, "get")) {
231
0
      name = propname(J);
232
0
      jsP_expect(J, '(');
233
0
      jsP_expect(J, ')');
234
0
      body = funbody(J);
235
0
      return EXP3(PROP_GET, name, NULL, body);
236
0
    }
237
0
    if (!strcmp(name->string, "set")) {
238
0
      name = propname(J);
239
0
      jsP_expect(J, '(');
240
0
      arg = identifier(J);
241
0
      jsP_expect(J, ')');
242
0
      body = funbody(J);
243
0
      return EXP3(PROP_SET, name, LIST(arg), body);
244
0
    }
245
0
  }
246
247
0
  jsP_expect(J, ':');
248
0
  value = assignment(J, 0);
249
0
  return EXP2(PROP_VAL, name, value);
250
0
}
251
252
static js_Ast *objectliteral(js_State *J)
253
0
{
254
0
  js_Ast *head, *tail;
255
0
  if (J->lookahead == '}')
256
0
    return NULL;
257
0
  head = tail = LIST(propassign(J));
258
0
  while (jsP_accept(J, ',')) {
259
0
    if (J->lookahead == '}')
260
0
      break;
261
0
    tail = tail->b = LIST(propassign(J));
262
0
  }
263
0
  return jsP_list(head);
264
0
}
265
266
/* Functions */
267
268
static js_Ast *parameters(js_State *J)
269
0
{
270
0
  js_Ast *head, *tail;
271
0
  if (J->lookahead == ')')
272
0
    return NULL;
273
0
  head = tail = LIST(identifier(J));
274
0
  while (jsP_accept(J, ',')) {
275
0
    tail = tail->b = LIST(identifier(J));
276
0
  }
277
0
  return jsP_list(head);
278
0
}
279
280
static js_Ast *fundec(js_State *J, int line)
281
0
{
282
0
  js_Ast *a, *b, *c;
283
0
  a = identifier(J);
284
0
  jsP_expect(J, '(');
285
0
  b = parameters(J);
286
0
  jsP_expect(J, ')');
287
0
  c = funbody(J);
288
0
  return jsP_newnode(J, AST_FUNDEC, line, a, b, c, 0);
289
0
}
290
291
static js_Ast *funstm(js_State *J, int line)
292
0
{
293
0
  js_Ast *a, *b, *c;
294
0
  a = identifier(J);
295
0
  jsP_expect(J, '(');
296
0
  b = parameters(J);
297
0
  jsP_expect(J, ')');
298
0
  c = funbody(J);
299
  /* rewrite function statement as "var X = function X() {}" */
300
0
  return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c))));
301
0
}
302
303
static js_Ast *funexp(js_State *J, int line)
304
0
{
305
0
  js_Ast *a, *b, *c;
306
0
  a = identifieropt(J);
307
0
  jsP_expect(J, '(');
308
0
  b = parameters(J);
309
0
  jsP_expect(J, ')');
310
0
  c = funbody(J);
311
0
  return EXP3(FUN, a, b, c);
312
0
}
313
314
/* Expressions */
315
316
static js_Ast *primary(js_State *J)
317
0
{
318
0
  js_Ast *a;
319
0
  int line = J->lexline;
320
321
0
  if (J->lookahead == TK_IDENTIFIER) {
322
0
    a = jsP_newstrnode(J, EXP_IDENTIFIER, J->text);
323
0
    jsP_next(J);
324
0
    return a;
325
0
  }
326
0
  if (J->lookahead == TK_STRING) {
327
0
    a = jsP_newstrnode(J, EXP_STRING, J->text);
328
0
    jsP_next(J);
329
0
    return a;
330
0
  }
331
0
  if (J->lookahead == TK_REGEXP) {
332
0
    a = jsP_newstrnode(J, EXP_REGEXP, J->text);
333
0
    a->number = J->number;
334
0
    jsP_next(J);
335
0
    return a;
336
0
  }
337
0
  if (J->lookahead == TK_NUMBER) {
338
0
    a = jsP_newnumnode(J, EXP_NUMBER, J->number);
339
0
    jsP_next(J);
340
0
    return a;
341
0
  }
342
343
0
  if (jsP_accept(J, TK_THIS)) return EXP0(THIS);
344
0
  if (jsP_accept(J, TK_NULL)) return EXP0(NULL);
345
0
  if (jsP_accept(J, TK_TRUE)) return EXP0(TRUE);
346
0
  if (jsP_accept(J, TK_FALSE)) return EXP0(FALSE);
347
0
  if (jsP_accept(J, '{')) {
348
0
    a = EXP1(OBJECT, objectliteral(J));
349
0
    jsP_expect(J, '}');
350
0
    return a;
351
0
  }
352
0
  if (jsP_accept(J, '[')) {
353
0
    a = EXP1(ARRAY, arrayliteral(J));
354
0
    jsP_expect(J, ']');
355
0
    return a;
356
0
  }
357
0
  if (jsP_accept(J, '(')) {
358
0
    a = expression(J, 0);
359
0
    jsP_expect(J, ')');
360
0
    return a;
361
0
  }
362
363
0
  jsP_error(J, "unexpected token in expression: %s", jsY_tokenstring(J->lookahead));
364
0
}
365
366
static js_Ast *arguments(js_State *J)
367
0
{
368
0
  js_Ast *head, *tail;
369
0
  if (J->lookahead == ')')
370
0
    return NULL;
371
0
  head = tail = LIST(assignment(J, 0));
372
0
  while (jsP_accept(J, ',')) {
373
0
    tail = tail->b = LIST(assignment(J, 0));
374
0
  }
375
0
  return jsP_list(head);
376
0
}
377
378
static js_Ast *newexp(js_State *J)
379
0
{
380
0
  js_Ast *a, *b;
381
0
  int line = J->lexline;
382
383
0
  if (jsP_accept(J, TK_NEW)) {
384
0
    a = memberexp(J);
385
0
    if (jsP_accept(J, '(')) {
386
0
      b = arguments(J);
387
0
      jsP_expect(J, ')');
388
0
      return EXP2(NEW, a, b);
389
0
    }
390
0
    return EXP1(NEW, a);
391
0
  }
392
393
0
  if (jsP_accept(J, TK_FUNCTION))
394
0
    return funexp(J, line);
395
396
0
  return primary(J);
397
0
}
398
399
static js_Ast *memberexp(js_State *J)
400
0
{
401
0
  js_Ast *a = newexp(J);
402
0
  int line;
403
0
  SAVEREC();
404
0
loop:
405
0
  INCREC();
406
0
  line = J->lexline;
407
0
  if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; }
408
0
  if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; }
409
0
  POPREC();
410
0
  return a;
411
0
}
412
413
static js_Ast *callexp(js_State *J)
414
0
{
415
0
  js_Ast *a = newexp(J);
416
0
  int line;
417
0
  SAVEREC();
418
0
loop:
419
0
  INCREC();
420
0
  line = J->lexline;
421
0
  if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; }
422
0
  if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; }
423
0
  if (jsP_accept(J, '(')) { a = EXP2(CALL, a, arguments(J)); jsP_expect(J, ')'); goto loop; }
424
0
  POPREC();
425
0
  return a;
426
0
}
427
428
static js_Ast *postfix(js_State *J)
429
0
{
430
0
  js_Ast *a = callexp(J);
431
0
  int line = J->lexline;
432
0
  if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a);
433
0
  if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a);
434
0
  return a;
435
0
}
436
437
static js_Ast *unary(js_State *J)
438
0
{
439
0
  js_Ast *a;
440
0
  int line = J->lexline;
441
0
  INCREC();
442
0
  if (jsP_accept(J, TK_DELETE)) a = EXP1(DELETE, unary(J));
443
0
  else if (jsP_accept(J, TK_VOID)) a = EXP1(VOID, unary(J));
444
0
  else if (jsP_accept(J, TK_TYPEOF)) a = EXP1(TYPEOF, unary(J));
445
0
  else if (jsP_accept(J, TK_INC)) a = EXP1(PREINC, unary(J));
446
0
  else if (jsP_accept(J, TK_DEC)) a = EXP1(PREDEC, unary(J));
447
0
  else if (jsP_accept(J, '+')) a = EXP1(POS, unary(J));
448
0
  else if (jsP_accept(J, '-')) a = EXP1(NEG, unary(J));
449
0
  else if (jsP_accept(J, '~')) a = EXP1(BITNOT, unary(J));
450
0
  else if (jsP_accept(J, '!')) a = EXP1(LOGNOT, unary(J));
451
0
  else a = postfix(J);
452
0
  DECREC();
453
0
  return a;
454
0
}
455
456
static js_Ast *multiplicative(js_State *J)
457
0
{
458
0
  js_Ast *a = unary(J);
459
0
  int line;
460
0
  SAVEREC();
461
0
loop:
462
0
  INCREC();
463
0
  line = J->lexline;
464
0
  if (jsP_accept(J, '*')) { a = EXP2(MUL, a, unary(J)); goto loop; }
465
0
  if (jsP_accept(J, '/')) { a = EXP2(DIV, a, unary(J)); goto loop; }
466
0
  if (jsP_accept(J, '%')) { a = EXP2(MOD, a, unary(J)); goto loop; }
467
0
  POPREC();
468
0
  return a;
469
0
}
470
471
static js_Ast *additive(js_State *J)
472
0
{
473
0
  js_Ast *a = multiplicative(J);
474
0
  int line;
475
0
  SAVEREC();
476
0
loop:
477
0
  INCREC();
478
0
  line = J->lexline;
479
0
  if (jsP_accept(J, '+')) { a = EXP2(ADD, a, multiplicative(J)); goto loop; }
480
0
  if (jsP_accept(J, '-')) { a = EXP2(SUB, a, multiplicative(J)); goto loop; }
481
0
  POPREC();
482
0
  return a;
483
0
}
484
485
static js_Ast *shift(js_State *J)
486
0
{
487
0
  js_Ast *a = additive(J);
488
0
  int line;
489
0
  SAVEREC();
490
0
loop:
491
0
  INCREC();
492
0
  line = J->lexline;
493
0
  if (jsP_accept(J, TK_SHL)) { a = EXP2(SHL, a, additive(J)); goto loop; }
494
0
  if (jsP_accept(J, TK_SHR)) { a = EXP2(SHR, a, additive(J)); goto loop; }
495
0
  if (jsP_accept(J, TK_USHR)) { a = EXP2(USHR, a, additive(J)); goto loop; }
496
0
  POPREC();
497
0
  return a;
498
0
}
499
500
static js_Ast *relational(js_State *J, int notin)
501
0
{
502
0
  js_Ast *a = shift(J);
503
0
  int line;
504
0
  SAVEREC();
505
0
loop:
506
0
  INCREC();
507
0
  line = J->lexline;
508
0
  if (jsP_accept(J, '<')) { a = EXP2(LT, a, shift(J)); goto loop; }
509
0
  if (jsP_accept(J, '>')) { a = EXP2(GT, a, shift(J)); goto loop; }
510
0
  if (jsP_accept(J, TK_LE)) { a = EXP2(LE, a, shift(J)); goto loop; }
511
0
  if (jsP_accept(J, TK_GE)) { a = EXP2(GE, a, shift(J)); goto loop; }
512
0
  if (jsP_accept(J, TK_INSTANCEOF)) { a = EXP2(INSTANCEOF, a, shift(J)); goto loop; }
513
0
  if (!notin && jsP_accept(J, TK_IN)) { a = EXP2(IN, a, shift(J)); goto loop; }
514
0
  POPREC();
515
0
  return a;
516
0
}
517
518
static js_Ast *equality(js_State *J, int notin)
519
0
{
520
0
  js_Ast *a = relational(J, notin);
521
0
  int line;
522
0
  SAVEREC();
523
0
loop:
524
0
  INCREC();
525
0
  line = J->lexline;
526
0
  if (jsP_accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; }
527
0
  if (jsP_accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; }
528
0
  if (jsP_accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; }
529
0
  if (jsP_accept(J, TK_STRICTNE)) { a = EXP2(STRICTNE, a, relational(J, notin)); goto loop; }
530
0
  POPREC();
531
0
  return a;
532
0
}
533
534
static js_Ast *bitand(js_State *J, int notin)
535
0
{
536
0
  js_Ast *a = equality(J, notin);
537
0
  SAVEREC();
538
0
  int line = J->lexline;
539
0
  while (jsP_accept(J, '&')) {
540
0
    INCREC();
541
0
    a = EXP2(BITAND, a, equality(J, notin));
542
0
    line = J->lexline;
543
0
  }
544
0
  POPREC();
545
0
  return a;
546
0
}
547
548
static js_Ast *bitxor(js_State *J, int notin)
549
0
{
550
0
  js_Ast *a = bitand(J, notin);
551
0
  SAVEREC();
552
0
  int line = J->lexline;
553
0
  while (jsP_accept(J, '^')) {
554
0
    INCREC();
555
0
    a = EXP2(BITXOR, a, bitand(J, notin));
556
0
    line = J->lexline;
557
0
  }
558
0
  POPREC();
559
0
  return a;
560
0
}
561
562
static js_Ast *bitor(js_State *J, int notin)
563
0
{
564
0
  js_Ast *a = bitxor(J, notin);
565
0
  SAVEREC();
566
0
  int line = J->lexline;
567
0
  while (jsP_accept(J, '|')) {
568
0
    INCREC();
569
0
    a = EXP2(BITOR, a, bitxor(J, notin));
570
0
    line = J->lexline;
571
0
  }
572
0
  POPREC();
573
0
  return a;
574
0
}
575
576
static js_Ast *logand(js_State *J, int notin)
577
0
{
578
0
  js_Ast *a = bitor(J, notin);
579
0
  int line = J->lexline;
580
0
  if (jsP_accept(J, TK_AND)) {
581
0
    INCREC();
582
0
    a = EXP2(LOGAND, a, logand(J, notin));
583
0
    DECREC();
584
0
  }
585
0
  return a;
586
0
}
587
588
static js_Ast *logor(js_State *J, int notin)
589
0
{
590
0
  js_Ast *a = logand(J, notin);
591
0
  int line = J->lexline;
592
0
  if (jsP_accept(J, TK_OR)) {
593
0
    INCREC();
594
0
    a = EXP2(LOGOR, a, logor(J, notin));
595
0
    DECREC();
596
0
  }
597
0
  return a;
598
0
}
599
600
static js_Ast *conditional(js_State *J, int notin)
601
0
{
602
0
  js_Ast *a = logor(J, notin);
603
0
  int line = J->lexline;
604
0
  if (jsP_accept(J, '?')) {
605
0
    js_Ast *b, *c;
606
0
    INCREC();
607
0
    b = assignment(J, 0);
608
0
    jsP_expect(J, ':');
609
0
    c = assignment(J, notin);
610
0
    DECREC();
611
0
    return EXP3(COND, a, b, c);
612
0
  }
613
0
  return a;
614
0
}
615
616
static js_Ast *assignment(js_State *J, int notin)
617
0
{
618
0
  js_Ast *a = conditional(J, notin);
619
0
  int line = J->lexline;
620
0
  INCREC();
621
0
  if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin));
622
0
  else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin));
623
0
  else if (jsP_accept(J, TK_DIV_ASS)) a = EXP2(ASS_DIV, a, assignment(J, notin));
624
0
  else if (jsP_accept(J, TK_MOD_ASS)) a = EXP2(ASS_MOD, a, assignment(J, notin));
625
0
  else if (jsP_accept(J, TK_ADD_ASS)) a = EXP2(ASS_ADD, a, assignment(J, notin));
626
0
  else if (jsP_accept(J, TK_SUB_ASS)) a = EXP2(ASS_SUB, a, assignment(J, notin));
627
0
  else if (jsP_accept(J, TK_SHL_ASS)) a = EXP2(ASS_SHL, a, assignment(J, notin));
628
0
  else if (jsP_accept(J, TK_SHR_ASS)) a = EXP2(ASS_SHR, a, assignment(J, notin));
629
0
  else if (jsP_accept(J, TK_USHR_ASS)) a = EXP2(ASS_USHR, a, assignment(J, notin));
630
0
  else if (jsP_accept(J, TK_AND_ASS)) a = EXP2(ASS_BITAND, a, assignment(J, notin));
631
0
  else if (jsP_accept(J, TK_XOR_ASS)) a = EXP2(ASS_BITXOR, a, assignment(J, notin));
632
0
  else if (jsP_accept(J, TK_OR_ASS)) a = EXP2(ASS_BITOR, a, assignment(J, notin));
633
0
  DECREC();
634
0
  return a;
635
0
}
636
637
static js_Ast *expression(js_State *J, int notin)
638
0
{
639
0
  js_Ast *a = assignment(J, notin);
640
0
  SAVEREC();
641
0
  int line = J->lexline;
642
0
  while (jsP_accept(J, ',')) {
643
0
    INCREC();
644
0
    a = EXP2(COMMA, a, assignment(J, notin));
645
0
    line = J->lexline;
646
0
  }
647
0
  POPREC();
648
0
  return a;
649
0
}
650
651
/* Statements */
652
653
static js_Ast *vardec(js_State *J, int notin)
654
0
{
655
0
  js_Ast *a = identifier(J);
656
0
  int line = J->lexline;
657
0
  if (jsP_accept(J, '='))
658
0
    return EXP2(VAR, a, assignment(J, notin));
659
0
  return EXP1(VAR, a);
660
0
}
661
662
static js_Ast *vardeclist(js_State *J, int notin)
663
0
{
664
0
  js_Ast *head, *tail;
665
0
  head = tail = LIST(vardec(J, notin));
666
0
  while (jsP_accept(J, ','))
667
0
    tail = tail->b = LIST(vardec(J, notin));
668
0
  return jsP_list(head);
669
0
}
670
671
static js_Ast *statementlist(js_State *J)
672
0
{
673
0
  js_Ast *head, *tail;
674
0
  if (J->lookahead == '}' || J->lookahead == TK_CASE || J->lookahead == TK_DEFAULT)
675
0
    return NULL;
676
0
  head = tail = LIST(statement(J));
677
0
  while (J->lookahead != '}' && J->lookahead != TK_CASE && J->lookahead != TK_DEFAULT)
678
0
    tail = tail->b = LIST(statement(J));
679
0
  return jsP_list(head);
680
0
}
681
682
static js_Ast *caseclause(js_State *J)
683
0
{
684
0
  js_Ast *a, *b;
685
0
  int line = J->lexline;
686
687
0
  if (jsP_accept(J, TK_CASE)) {
688
0
    a = expression(J, 0);
689
0
    jsP_expect(J, ':');
690
0
    b = statementlist(J);
691
0
    return STM2(CASE, a, b);
692
0
  }
693
694
0
  if (jsP_accept(J, TK_DEFAULT)) {
695
0
    jsP_expect(J, ':');
696
0
    a = statementlist(J);
697
0
    return STM1(DEFAULT, a);
698
0
  }
699
700
0
  jsP_error(J, "unexpected token in switch: %s (expected 'case' or 'default')", jsY_tokenstring(J->lookahead));
701
0
}
702
703
static js_Ast *caselist(js_State *J)
704
0
{
705
0
  js_Ast *head, *tail;
706
0
  if (J->lookahead == '}')
707
0
    return NULL;
708
0
  head = tail = LIST(caseclause(J));
709
0
  while (J->lookahead != '}')
710
0
    tail = tail->b = LIST(caseclause(J));
711
0
  return jsP_list(head);
712
0
}
713
714
static js_Ast *block(js_State *J)
715
0
{
716
0
  js_Ast *a;
717
0
  int line = J->lexline;
718
0
  jsP_expect(J, '{');
719
0
  a = statementlist(J);
720
0
  jsP_expect(J, '}');
721
0
  return STM1(BLOCK, a);
722
0
}
723
724
static js_Ast *forexpression(js_State *J, int end)
725
0
{
726
0
  js_Ast *a = NULL;
727
0
  if (J->lookahead != end)
728
0
    a = expression(J, 0);
729
0
  jsP_expect(J, end);
730
0
  return a;
731
0
}
732
733
static js_Ast *forstatement(js_State *J, int line)
734
0
{
735
0
  js_Ast *a, *b, *c, *d;
736
0
  jsP_expect(J, '(');
737
0
  if (jsP_accept(J, TK_VAR)) {
738
0
    a = vardeclist(J, 1);
739
0
    if (jsP_accept(J, ';')) {
740
0
      b = forexpression(J, ';');
741
0
      c = forexpression(J, ')');
742
0
      d = statement(J);
743
0
      return STM4(FOR_VAR, a, b, c, d);
744
0
    }
745
0
    if (jsP_accept(J, TK_IN)) {
746
0
      b = expression(J, 0);
747
0
      jsP_expect(J, ')');
748
0
      c = statement(J);
749
0
      return STM3(FOR_IN_VAR, a, b, c);
750
0
    }
751
0
    jsP_error(J, "unexpected token in for-var-statement: %s", jsY_tokenstring(J->lookahead));
752
0
  }
753
754
0
  if (J->lookahead != ';')
755
0
    a = expression(J, 1);
756
0
  else
757
0
    a = NULL;
758
0
  if (jsP_accept(J, ';')) {
759
0
    b = forexpression(J, ';');
760
0
    c = forexpression(J, ')');
761
0
    d = statement(J);
762
0
    return STM4(FOR, a, b, c, d);
763
0
  }
764
0
  if (jsP_accept(J, TK_IN)) {
765
0
    b = expression(J, 0);
766
0
    jsP_expect(J, ')');
767
0
    c = statement(J);
768
0
    return STM3(FOR_IN, a, b, c);
769
0
  }
770
0
  jsP_error(J, "unexpected token in for-statement: %s", jsY_tokenstring(J->lookahead));
771
0
}
772
773
static js_Ast *statement(js_State *J)
774
0
{
775
0
  js_Ast *a, *b, *c, *d;
776
0
  js_Ast *stm;
777
0
  int line = J->lexline;
778
779
0
  INCREC();
780
781
0
  if (J->lookahead == '{') {
782
0
    stm = block(J);
783
0
  }
784
785
0
  else if (jsP_accept(J, TK_VAR)) {
786
0
    a = vardeclist(J, 0);
787
0
    semicolon(J);
788
0
    stm = STM1(VAR, a);
789
0
  }
790
791
  /* empty statement */
792
0
  else if (jsP_accept(J, ';')) {
793
0
    stm = STM0(EMPTY);
794
0
  }
795
796
0
  else if (jsP_accept(J, TK_IF)) {
797
0
    jsP_expect(J, '(');
798
0
    a = expression(J, 0);
799
0
    jsP_expect(J, ')');
800
0
    b = statement(J);
801
0
    if (jsP_accept(J, TK_ELSE))
802
0
      c = statement(J);
803
0
    else
804
0
      c = NULL;
805
0
    stm = STM3(IF, a, b, c);
806
0
  }
807
808
0
  else if (jsP_accept(J, TK_DO)) {
809
0
    a = statement(J);
810
0
    jsP_expect(J, TK_WHILE);
811
0
    jsP_expect(J, '(');
812
0
    b = expression(J, 0);
813
0
    jsP_expect(J, ')');
814
0
    semicolon(J);
815
0
    stm = STM2(DO, a, b);
816
0
  }
817
818
0
  else if (jsP_accept(J, TK_WHILE)) {
819
0
    jsP_expect(J, '(');
820
0
    a = expression(J, 0);
821
0
    jsP_expect(J, ')');
822
0
    b = statement(J);
823
0
    stm = STM2(WHILE, a, b);
824
0
  }
825
826
0
  else if (jsP_accept(J, TK_FOR)) {
827
0
    stm = forstatement(J, line);
828
0
  }
829
830
0
  else if (jsP_accept(J, TK_CONTINUE)) {
831
0
    a = identifieropt(J);
832
0
    semicolon(J);
833
0
    stm = STM1(CONTINUE, a);
834
0
  }
835
836
0
  else if (jsP_accept(J, TK_BREAK)) {
837
0
    a = identifieropt(J);
838
0
    semicolon(J);
839
0
    stm = STM1(BREAK, a);
840
0
  }
841
842
0
  else if (jsP_accept(J, TK_RETURN)) {
843
0
    if (J->lookahead != ';' && J->lookahead != '}' && J->lookahead != 0)
844
0
      a = expression(J, 0);
845
0
    else
846
0
      a = NULL;
847
0
    semicolon(J);
848
0
    stm = STM1(RETURN, a);
849
0
  }
850
851
0
  else if (jsP_accept(J, TK_WITH)) {
852
0
    jsP_expect(J, '(');
853
0
    a = expression(J, 0);
854
0
    jsP_expect(J, ')');
855
0
    b = statement(J);
856
0
    stm = STM2(WITH, a, b);
857
0
  }
858
859
0
  else if (jsP_accept(J, TK_SWITCH)) {
860
0
    jsP_expect(J, '(');
861
0
    a = expression(J, 0);
862
0
    jsP_expect(J, ')');
863
0
    jsP_expect(J, '{');
864
0
    b = caselist(J);
865
0
    jsP_expect(J, '}');
866
0
    stm = STM2(SWITCH, a, b);
867
0
  }
868
869
0
  else if (jsP_accept(J, TK_THROW)) {
870
0
    a = expression(J, 0);
871
0
    semicolon(J);
872
0
    stm = STM1(THROW, a);
873
0
  }
874
875
0
  else if (jsP_accept(J, TK_TRY)) {
876
0
    a = block(J);
877
0
    b = c = d = NULL;
878
0
    if (jsP_accept(J, TK_CATCH)) {
879
0
      jsP_expect(J, '(');
880
0
      b = identifier(J);
881
0
      jsP_expect(J, ')');
882
0
      c = block(J);
883
0
    }
884
0
    if (jsP_accept(J, TK_FINALLY)) {
885
0
      d = block(J);
886
0
    }
887
0
    if (!b && !d)
888
0
      jsP_error(J, "unexpected token in try: %s (expected 'catch' or 'finally')", jsY_tokenstring(J->lookahead));
889
0
    stm = STM4(TRY, a, b, c, d);
890
0
  }
891
892
0
  else if (jsP_accept(J, TK_DEBUGGER)) {
893
0
    semicolon(J);
894
0
    stm = STM0(DEBUGGER);
895
0
  }
896
897
0
  else if (jsP_accept(J, TK_FUNCTION)) {
898
0
    jsP_warning(J, "function statements are not standard");
899
0
    stm = funstm(J, line);
900
0
  }
901
902
  /* labelled statement or expression statement */
903
0
  else if (J->lookahead == TK_IDENTIFIER) {
904
0
    a = expression(J, 0);
905
0
    if (a->type == EXP_IDENTIFIER && jsP_accept(J, ':')) {
906
0
      a->type = AST_IDENTIFIER;
907
0
      b = statement(J);
908
0
      stm = STM2(LABEL, a, b);
909
0
    } else {
910
0
      semicolon(J);
911
0
      stm = a;
912
0
    }
913
0
  }
914
915
  /* expression statement */
916
0
  else {
917
0
    stm = expression(J, 0);
918
0
    semicolon(J);
919
0
  }
920
921
0
  DECREC();
922
0
  return stm;
923
0
}
924
925
/* Program */
926
927
static js_Ast *scriptelement(js_State *J)
928
0
{
929
0
  int line = J->lexline;
930
0
  if (jsP_accept(J, TK_FUNCTION))
931
0
    return fundec(J, line);
932
0
  return statement(J);
933
0
}
934
935
static js_Ast *script(js_State *J, int terminator)
936
0
{
937
0
  js_Ast *head, *tail;
938
0
  if (J->lookahead == terminator)
939
0
    return NULL;
940
0
  head = tail = LIST(scriptelement(J));
941
0
  while (J->lookahead != terminator)
942
0
    tail = tail->b = LIST(scriptelement(J));
943
0
  return jsP_list(head);
944
0
}
945
946
static js_Ast *funbody(js_State *J)
947
0
{
948
0
  js_Ast *a;
949
0
  jsP_expect(J, '{');
950
0
  a = script(J, '}');
951
0
  jsP_expect(J, '}');
952
0
  return a;
953
0
}
954
955
/* Constant folding */
956
957
static int toint32(double d)
958
0
{
959
0
  double two32 = 4294967296.0;
960
0
  double two31 = 2147483648.0;
961
962
0
  if (!isfinite(d) || d == 0)
963
0
    return 0;
964
965
0
  d = fmod(d, two32);
966
0
  d = d >= 0 ? floor(d) : ceil(d) + two32;
967
0
  if (d >= two31)
968
0
    return d - two32;
969
0
  else
970
0
    return d;
971
0
}
972
973
static unsigned int touint32(double d)
974
0
{
975
0
  return (unsigned int)toint32(d);
976
0
}
977
978
static int jsP_setnumnode(js_Ast *node, double x)
979
0
{
980
0
  node->type = EXP_NUMBER;
981
0
  node->number = x;
982
0
  node->a = node->b = node->c = node->d = NULL;
983
0
  return 1;
984
0
}
985
986
static int jsP_foldconst(js_Ast *node)
987
0
{
988
0
  double x, y;
989
0
  int a, b;
990
991
0
  if (node->type == AST_LIST) {
992
0
    while (node) {
993
0
      jsP_foldconst(node->a);
994
0
      node = node->b;
995
0
    }
996
0
    return 0;
997
0
  }
998
999
0
  if (node->type == EXP_NUMBER)
1000
0
    return 1;
1001
1002
0
  a = node->a ? jsP_foldconst(node->a) : 0;
1003
0
  b = node->b ? jsP_foldconst(node->b) : 0;
1004
0
  if (node->c) jsP_foldconst(node->c);
1005
0
  if (node->d) jsP_foldconst(node->d);
1006
1007
0
  if (a) {
1008
0
    x = node->a->number;
1009
0
    switch (node->type) {
1010
0
    default: break;
1011
0
    case EXP_NEG: return jsP_setnumnode(node, -x);
1012
0
    case EXP_POS: return jsP_setnumnode(node, x);
1013
0
    case EXP_BITNOT: return jsP_setnumnode(node, ~toint32(x));
1014
0
    }
1015
1016
0
    if (b) {
1017
0
      y = node->b->number;
1018
0
      switch (node->type) {
1019
0
      default: break;
1020
0
      case EXP_MUL: return jsP_setnumnode(node, x * y);
1021
0
      case EXP_DIV: return jsP_setnumnode(node, x / y);
1022
0
      case EXP_MOD: return jsP_setnumnode(node, fmod(x, y));
1023
0
      case EXP_ADD: return jsP_setnumnode(node, x + y);
1024
0
      case EXP_SUB: return jsP_setnumnode(node, x - y);
1025
0
      case EXP_SHL: return jsP_setnumnode(node, toint32(x) << (touint32(y) & 0x1F));
1026
0
      case EXP_SHR: return jsP_setnumnode(node, toint32(x) >> (touint32(y) & 0x1F));
1027
0
      case EXP_USHR: return jsP_setnumnode(node, touint32(x) >> (touint32(y) & 0x1F));
1028
0
      case EXP_BITAND: return jsP_setnumnode(node, toint32(x) & toint32(y));
1029
0
      case EXP_BITXOR: return jsP_setnumnode(node, toint32(x) ^ toint32(y));
1030
0
      case EXP_BITOR: return jsP_setnumnode(node, toint32(x) | toint32(y));
1031
0
      }
1032
0
    }
1033
0
  }
1034
1035
0
  return 0;
1036
0
}
1037
1038
/* Main entry point */
1039
1040
js_Ast *jsP_parse(js_State *J, const char *filename, const char *source)
1041
0
{
1042
0
  js_Ast *p;
1043
1044
0
  jsY_initlex(J, filename, source);
1045
0
  jsP_next(J);
1046
0
  J->astdepth = 0;
1047
0
  p = script(J, 0);
1048
0
  if (p)
1049
0
    jsP_foldconst(p);
1050
1051
0
  return p;
1052
0
}
1053
1054
js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body)
1055
0
{
1056
0
  js_Ast *p = NULL;
1057
0
  int line = 0;
1058
0
  if (params) {
1059
0
    jsY_initlex(J, filename, params);
1060
0
    jsP_next(J);
1061
0
    J->astdepth = 0;
1062
0
    p = parameters(J);
1063
0
  }
1064
0
  return EXP3(FUN, NULL, p, jsP_parse(J, filename, body));
1065
0
}