Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7641 views
1
#include "jsi.h"
2
#include "jslex.h"
3
#include "utf.h"
4
5
JS_NORETURN static void jsY_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3);
6
7
static void jsY_error(js_State *J, const char *fmt, ...)
8
{
9
va_list ap;
10
char buf[512];
11
char msgbuf[256];
12
13
va_start(ap, fmt);
14
vsnprintf(msgbuf, 256, fmt, ap);
15
va_end(ap);
16
17
snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline);
18
strcat(buf, msgbuf);
19
20
js_newsyntaxerror(J, buf);
21
js_throw(J);
22
}
23
24
static const char *tokenstring[] = {
25
"(end-of-file)",
26
"'\\x01'", "'\\x02'", "'\\x03'", "'\\x04'", "'\\x05'", "'\\x06'", "'\\x07'",
27
"'\\x08'", "'\\x09'", "'\\x0A'", "'\\x0B'", "'\\x0C'", "'\\x0D'", "'\\x0E'", "'\\x0F'",
28
"'\\x10'", "'\\x11'", "'\\x12'", "'\\x13'", "'\\x14'", "'\\x15'", "'\\x16'", "'\\x17'",
29
"'\\x18'", "'\\x19'", "'\\x1A'", "'\\x1B'", "'\\x1C'", "'\\x1D'", "'\\x1E'", "'\\x1F'",
30
"' '", "'!'", "'\"'", "'#'", "'$'", "'%'", "'&'", "'\\''",
31
"'('", "')'", "'*'", "'+'", "','", "'-'", "'.'", "'/'",
32
"'0'", "'1'", "'2'", "'3'", "'4'", "'5'", "'6'", "'7'",
33
"'8'", "'9'", "':'", "';'", "'<'", "'='", "'>'", "'?'",
34
"'@'", "'A'", "'B'", "'C'", "'D'", "'E'", "'F'", "'G'",
35
"'H'", "'I'", "'J'", "'K'", "'L'", "'M'", "'N'", "'O'",
36
"'P'", "'Q'", "'R'", "'S'", "'T'", "'U'", "'V'", "'W'",
37
"'X'", "'Y'", "'Z'", "'['", "'\'", "']'", "'^'", "'_'",
38
"'`'", "'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'",
39
"'h'", "'i'", "'j'", "'k'", "'l'", "'m'", "'n'", "'o'",
40
"'p'", "'q'", "'r'", "'s'", "'t'", "'u'", "'v'", "'w'",
41
"'x'", "'y'", "'z'", "'{'", "'|'", "'}'", "'~'", "'\\x7F'",
42
43
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
44
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
45
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
46
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
47
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
48
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
49
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
50
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
51
52
"(identifier)", "(number)", "(string)", "(regexp)",
53
54
"'<='", "'>='", "'=='", "'!='", "'==='", "'!=='",
55
"'<<'", "'>>'", "'>>>'", "'&&'", "'||'",
56
"'+='", "'-='", "'*='", "'/='", "'%='",
57
"'<<='", "'>>='", "'>>>='", "'&='", "'|='", "'^='",
58
"'++'", "'--'",
59
60
"'break'", "'case'", "'catch'", "'continue'", "'debugger'",
61
"'default'", "'delete'", "'do'", "'else'", "'false'", "'finally'", "'for'",
62
"'function'", "'if'", "'in'", "'instanceof'", "'new'", "'null'", "'return'",
63
"'switch'", "'this'", "'throw'", "'true'", "'try'", "'typeof'", "'var'",
64
"'void'", "'while'", "'with'",
65
};
66
67
const char *jsY_tokenstring(int token)
68
{
69
if (token >= 0 && token < (int)nelem(tokenstring))
70
if (tokenstring[token])
71
return tokenstring[token];
72
return "<unknown>";
73
}
74
75
static const char *keywords[] = {
76
"break", "case", "catch", "continue", "debugger", "default", "delete",
77
"do", "else", "false", "finally", "for", "function", "if", "in",
78
"instanceof", "new", "null", "return", "switch", "this", "throw",
79
"true", "try", "typeof", "var", "void", "while", "with",
80
};
81
82
int jsY_findword(const char *s, const char **list, int num)
83
{
84
int l = 0;
85
int r = num - 1;
86
while (l <= r) {
87
int m = (l + r) >> 1;
88
int c = strcmp(s, list[m]);
89
if (c < 0)
90
r = m - 1;
91
else if (c > 0)
92
l = m + 1;
93
else
94
return m;
95
}
96
return -1;
97
}
98
99
static int jsY_findkeyword(js_State *J, const char *s)
100
{
101
int i = jsY_findword(s, keywords, nelem(keywords));
102
if (i >= 0) {
103
J->text = keywords[i];
104
return TK_BREAK + i; /* first keyword + i */
105
}
106
J->text = js_intern(J, s);
107
return TK_IDENTIFIER;
108
}
109
110
int jsY_iswhite(int c)
111
{
112
return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF;
113
}
114
115
int jsY_isnewline(int c)
116
{
117
return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
118
}
119
120
#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
121
#define isdigit(c) (c >= '0' && c <= '9')
122
#define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
123
124
static int jsY_isidentifierstart(int c)
125
{
126
return isalpha(c) || c == '$' || c == '_' || isalpharune(c);
127
}
128
129
static int jsY_isidentifierpart(int c)
130
{
131
return isdigit(c) || isalpha(c) || c == '$' || c == '_' || isalpharune(c);
132
}
133
134
static int jsY_isdec(int c)
135
{
136
return isdigit(c);
137
}
138
139
int jsY_ishex(int c)
140
{
141
return isdigit(c) || ishex(c);
142
}
143
144
int jsY_tohex(int c)
145
{
146
if (c >= '0' && c <= '9') return c - '0';
147
if (c >= 'a' && c <= 'f') return c - 'a' + 0xA;
148
if (c >= 'A' && c <= 'F') return c - 'A' + 0xA;
149
return 0;
150
}
151
152
static void jsY_next(js_State *J)
153
{
154
Rune c;
155
J->source += chartorune(&c, J->source);
156
/* consume CR LF as one unit */
157
if (c == '\r' && *J->source == '\n')
158
++J->source;
159
if (jsY_isnewline(c)) {
160
J->line++;
161
c = '\n';
162
}
163
J->lexchar = c;
164
}
165
166
#define jsY_accept(J, x) (J->lexchar == x ? (jsY_next(J), 1) : 0)
167
168
#define jsY_expect(J, x) if (!jsY_accept(J, x)) jsY_error(J, "expected '%c'", x)
169
170
static void jsY_unescape(js_State *J)
171
{
172
if (jsY_accept(J, '\\')) {
173
if (jsY_accept(J, 'u')) {
174
int x = 0;
175
if (!jsY_ishex(J->lexchar)) goto error; x |= jsY_tohex(J->lexchar) << 12; jsY_next(J);
176
if (!jsY_ishex(J->lexchar)) goto error; x |= jsY_tohex(J->lexchar) << 8; jsY_next(J);
177
if (!jsY_ishex(J->lexchar)) goto error; x |= jsY_tohex(J->lexchar) << 4; jsY_next(J);
178
if (!jsY_ishex(J->lexchar)) goto error; x |= jsY_tohex(J->lexchar);
179
J->lexchar = x;
180
return;
181
}
182
error:
183
jsY_error(J, "unexpected escape sequence");
184
}
185
}
186
187
static void textinit(js_State *J)
188
{
189
if (!J->lexbuf.text) {
190
J->lexbuf.cap = 4096;
191
J->lexbuf.text = js_malloc(J, J->lexbuf.cap);
192
}
193
J->lexbuf.len = 0;
194
}
195
196
static void textpush(js_State *J, Rune c)
197
{
198
int n = runelen(c);
199
if (J->lexbuf.len + n > J->lexbuf.cap) {
200
J->lexbuf.cap = J->lexbuf.cap * 2;
201
J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap);
202
}
203
J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c);
204
}
205
206
static char *textend(js_State *J)
207
{
208
textpush(J, 0);
209
return J->lexbuf.text;
210
}
211
212
static void lexlinecomment(js_State *J)
213
{
214
while (J->lexchar && J->lexchar != '\n')
215
jsY_next(J);
216
}
217
218
static int lexcomment(js_State *J)
219
{
220
/* already consumed initial '/' '*' sequence */
221
while (J->lexchar != 0) {
222
if (jsY_accept(J, '*')) {
223
while (J->lexchar == '*')
224
jsY_next(J);
225
if (jsY_accept(J, '/'))
226
return 0;
227
}
228
jsY_next(J);
229
}
230
return -1;
231
}
232
233
static double lexhex(js_State *J)
234
{
235
double n = 0;
236
if (!jsY_ishex(J->lexchar))
237
jsY_error(J, "malformed hexadecimal number");
238
while (jsY_ishex(J->lexchar)) {
239
n = n * 16 + jsY_tohex(J->lexchar);
240
jsY_next(J);
241
}
242
return n;
243
}
244
245
#if 0
246
247
static double lexinteger(js_State *J)
248
{
249
double n = 0;
250
if (!jsY_isdec(J->lexchar))
251
jsY_error(J, "malformed number");
252
while (jsY_isdec(J->lexchar)) {
253
n = n * 10 + (J->lexchar - '0');
254
jsY_next(J);
255
}
256
return n;
257
}
258
259
static double lexfraction(js_State *J)
260
{
261
double n = 0;
262
double d = 1;
263
while (jsY_isdec(J->lexchar)) {
264
n = n * 10 + (J->lexchar - '0');
265
d = d * 10;
266
jsY_next(J);
267
}
268
return n / d;
269
}
270
271
static double lexexponent(js_State *J)
272
{
273
double sign;
274
if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
275
if (jsY_accept(J, '-')) sign = -1;
276
else if (jsY_accept(J, '+')) sign = 1;
277
else sign = 1;
278
return sign * lexinteger(J);
279
}
280
return 0;
281
}
282
283
static int lexnumber(js_State *J)
284
{
285
double n;
286
double e;
287
288
if (jsY_accept(J, '0')) {
289
if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {
290
J->number = lexhex(J);
291
return TK_NUMBER;
292
}
293
if (jsY_isdec(J->lexchar))
294
jsY_error(J, "number with leading zero");
295
n = 0;
296
if (jsY_accept(J, '.'))
297
n += lexfraction(J);
298
} else if (jsY_accept(J, '.')) {
299
if (!jsY_isdec(J->lexchar))
300
return '.';
301
n = lexfraction(J);
302
} else {
303
n = lexinteger(J);
304
if (jsY_accept(J, '.'))
305
n += lexfraction(J);
306
}
307
308
e = lexexponent(J);
309
if (e < 0)
310
n /= pow(10, -e);
311
else if (e > 0)
312
n *= pow(10, e);
313
314
if (jsY_isidentifierstart(J->lexchar))
315
jsY_error(J, "number with letter suffix");
316
317
J->number = n;
318
return TK_NUMBER;
319
}
320
321
#else
322
323
static int lexnumber(js_State *J)
324
{
325
const char *s = J->source - 1;
326
327
if (jsY_accept(J, '0')) {
328
if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {
329
J->number = lexhex(J);
330
return TK_NUMBER;
331
}
332
if (jsY_isdec(J->lexchar))
333
jsY_error(J, "number with leading zero");
334
if (jsY_accept(J, '.')) {
335
while (jsY_isdec(J->lexchar))
336
jsY_next(J);
337
}
338
} else if (jsY_accept(J, '.')) {
339
if (!jsY_isdec(J->lexchar))
340
return '.';
341
while (jsY_isdec(J->lexchar))
342
jsY_next(J);
343
} else {
344
while (jsY_isdec(J->lexchar))
345
jsY_next(J);
346
if (jsY_accept(J, '.')) {
347
while (jsY_isdec(J->lexchar))
348
jsY_next(J);
349
}
350
}
351
352
if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
353
if (J->lexchar == '-' || J->lexchar == '+')
354
jsY_next(J);
355
while (jsY_isdec(J->lexchar))
356
jsY_next(J);
357
}
358
359
if (jsY_isidentifierstart(J->lexchar))
360
jsY_error(J, "number with letter suffix");
361
362
J->number = js_strtod(s, NULL);
363
return TK_NUMBER;
364
365
}
366
367
#endif
368
369
static int lexescape(js_State *J)
370
{
371
int x = 0;
372
373
/* already consumed '\' */
374
375
if (jsY_accept(J, '\n'))
376
return 0;
377
378
switch (J->lexchar) {
379
case 'u':
380
jsY_next(J);
381
if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); }
382
if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); }
383
if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
384
if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
385
textpush(J, x);
386
break;
387
case 'x':
388
jsY_next(J);
389
if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
390
if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
391
textpush(J, x);
392
break;
393
case '0': textpush(J, 0); jsY_next(J); break;
394
case '\\': textpush(J, '\\'); jsY_next(J); break;
395
case '\'': textpush(J, '\''); jsY_next(J); break;
396
case '"': textpush(J, '"'); jsY_next(J); break;
397
case 'b': textpush(J, '\b'); jsY_next(J); break;
398
case 'f': textpush(J, '\f'); jsY_next(J); break;
399
case 'n': textpush(J, '\n'); jsY_next(J); break;
400
case 'r': textpush(J, '\r'); jsY_next(J); break;
401
case 't': textpush(J, '\t'); jsY_next(J); break;
402
case 'v': textpush(J, '\v'); jsY_next(J); break;
403
default: textpush(J, J->lexchar); jsY_next(J); break;
404
}
405
return 0;
406
}
407
408
static int lexstring(js_State *J)
409
{
410
const char *s;
411
412
int q = J->lexchar;
413
jsY_next(J);
414
415
textinit(J);
416
417
while (J->lexchar != q) {
418
if (J->lexchar == 0 || J->lexchar == '\n')
419
jsY_error(J, "string not terminated");
420
if (jsY_accept(J, '\\')) {
421
if (lexescape(J))
422
jsY_error(J, "malformed escape sequence");
423
} else {
424
textpush(J, J->lexchar);
425
jsY_next(J);
426
}
427
}
428
jsY_expect(J, q);
429
430
s = textend(J);
431
432
J->text = js_intern(J, s);
433
return TK_STRING;
434
}
435
436
/* the ugliest language wart ever... */
437
static int isregexpcontext(int last)
438
{
439
switch (last) {
440
case ']':
441
case ')':
442
case '}':
443
case TK_IDENTIFIER:
444
case TK_NUMBER:
445
case TK_STRING:
446
case TK_FALSE:
447
case TK_NULL:
448
case TK_THIS:
449
case TK_TRUE:
450
return 0;
451
default:
452
return 1;
453
}
454
}
455
456
static int lexregexp(js_State *J)
457
{
458
const char *s;
459
int g, m, i;
460
int inclass = 0;
461
462
/* already consumed initial '/' */
463
464
textinit(J);
465
466
/* regexp body */
467
while (J->lexchar != '/' || inclass) {
468
if (J->lexchar == 0 || J->lexchar == '\n') {
469
jsY_error(J, "regular expression not terminated");
470
} else if (jsY_accept(J, '\\')) {
471
if (jsY_accept(J, '/')) {
472
textpush(J, '/');
473
} else {
474
textpush(J, '\\');
475
if (J->lexchar == 0 || J->lexchar == '\n')
476
jsY_error(J, "regular expression not terminated");
477
textpush(J, J->lexchar);
478
jsY_next(J);
479
}
480
} else {
481
if (J->lexchar == '[' && !inclass)
482
inclass = 1;
483
if (J->lexchar == ']' && inclass)
484
inclass = 0;
485
textpush(J, J->lexchar);
486
jsY_next(J);
487
}
488
}
489
jsY_expect(J, '/');
490
491
s = textend(J);
492
493
/* regexp flags */
494
g = i = m = 0;
495
496
while (jsY_isidentifierpart(J->lexchar)) {
497
if (jsY_accept(J, 'g')) ++g;
498
else if (jsY_accept(J, 'i')) ++i;
499
else if (jsY_accept(J, 'm')) ++m;
500
else jsY_error(J, "illegal flag in regular expression: %c", J->lexchar);
501
}
502
503
if (g > 1 || i > 1 || m > 1)
504
jsY_error(J, "duplicated flag in regular expression");
505
506
J->text = js_intern(J, s);
507
J->number = 0;
508
if (g) J->number += JS_REGEXP_G;
509
if (i) J->number += JS_REGEXP_I;
510
if (m) J->number += JS_REGEXP_M;
511
return TK_REGEXP;
512
}
513
514
/* simple "return [no Line Terminator here] ..." contexts */
515
static int isnlthcontext(int last)
516
{
517
switch (last) {
518
case TK_BREAK:
519
case TK_CONTINUE:
520
case TK_RETURN:
521
case TK_THROW:
522
return 1;
523
default:
524
return 0;
525
}
526
}
527
528
static int jsY_lexx(js_State *J)
529
{
530
J->newline = 0;
531
532
while (1) {
533
J->lexline = J->line; /* save location of beginning of token */
534
535
while (jsY_iswhite(J->lexchar))
536
jsY_next(J);
537
538
if (jsY_accept(J, '\n')) {
539
J->newline = 1;
540
if (isnlthcontext(J->lasttoken))
541
return ';';
542
continue;
543
}
544
545
if (jsY_accept(J, '/')) {
546
if (jsY_accept(J, '/')) {
547
lexlinecomment(J);
548
continue;
549
} else if (jsY_accept(J, '*')) {
550
if (lexcomment(J))
551
jsY_error(J, "multi-line comment not terminated");
552
continue;
553
} else if (isregexpcontext(J->lasttoken)) {
554
return lexregexp(J);
555
} else if (jsY_accept(J, '=')) {
556
return TK_DIV_ASS;
557
} else {
558
return '/';
559
}
560
}
561
562
if (J->lexchar >= '0' && J->lexchar <= '9') {
563
return lexnumber(J);
564
}
565
566
switch (J->lexchar) {
567
case '(': jsY_next(J); return '(';
568
case ')': jsY_next(J); return ')';
569
case ',': jsY_next(J); return ',';
570
case ':': jsY_next(J); return ':';
571
case ';': jsY_next(J); return ';';
572
case '?': jsY_next(J); return '?';
573
case '[': jsY_next(J); return '[';
574
case ']': jsY_next(J); return ']';
575
case '{': jsY_next(J); return '{';
576
case '}': jsY_next(J); return '}';
577
case '~': jsY_next(J); return '~';
578
579
case '\'':
580
case '"':
581
return lexstring(J);
582
583
case '.':
584
return lexnumber(J);
585
586
case '<':
587
jsY_next(J);
588
if (jsY_accept(J, '<')) {
589
if (jsY_accept(J, '='))
590
return TK_SHL_ASS;
591
return TK_SHL;
592
}
593
if (jsY_accept(J, '='))
594
return TK_LE;
595
return '<';
596
597
case '>':
598
jsY_next(J);
599
if (jsY_accept(J, '>')) {
600
if (jsY_accept(J, '>')) {
601
if (jsY_accept(J, '='))
602
return TK_USHR_ASS;
603
return TK_USHR;
604
}
605
if (jsY_accept(J, '='))
606
return TK_SHR_ASS;
607
return TK_SHR;
608
}
609
if (jsY_accept(J, '='))
610
return TK_GE;
611
return '>';
612
613
case '=':
614
jsY_next(J);
615
if (jsY_accept(J, '=')) {
616
if (jsY_accept(J, '='))
617
return TK_STRICTEQ;
618
return TK_EQ;
619
}
620
return '=';
621
622
case '!':
623
jsY_next(J);
624
if (jsY_accept(J, '=')) {
625
if (jsY_accept(J, '='))
626
return TK_STRICTNE;
627
return TK_NE;
628
}
629
return '!';
630
631
case '+':
632
jsY_next(J);
633
if (jsY_accept(J, '+'))
634
return TK_INC;
635
if (jsY_accept(J, '='))
636
return TK_ADD_ASS;
637
return '+';
638
639
case '-':
640
jsY_next(J);
641
if (jsY_accept(J, '-'))
642
return TK_DEC;
643
if (jsY_accept(J, '='))
644
return TK_SUB_ASS;
645
return '-';
646
647
case '*':
648
jsY_next(J);
649
if (jsY_accept(J, '='))
650
return TK_MUL_ASS;
651
return '*';
652
653
case '%':
654
jsY_next(J);
655
if (jsY_accept(J, '='))
656
return TK_MOD_ASS;
657
return '%';
658
659
case '&':
660
jsY_next(J);
661
if (jsY_accept(J, '&'))
662
return TK_AND;
663
if (jsY_accept(J, '='))
664
return TK_AND_ASS;
665
return '&';
666
667
case '|':
668
jsY_next(J);
669
if (jsY_accept(J, '|'))
670
return TK_OR;
671
if (jsY_accept(J, '='))
672
return TK_OR_ASS;
673
return '|';
674
675
case '^':
676
jsY_next(J);
677
if (jsY_accept(J, '='))
678
return TK_XOR_ASS;
679
return '^';
680
681
case 0:
682
return 0; /* EOF */
683
}
684
685
/* Handle \uXXXX escapes in identifiers */
686
jsY_unescape(J);
687
if (jsY_isidentifierstart(J->lexchar)) {
688
textinit(J);
689
textpush(J, J->lexchar);
690
691
jsY_next(J);
692
jsY_unescape(J);
693
while (jsY_isidentifierpart(J->lexchar)) {
694
textpush(J, J->lexchar);
695
jsY_next(J);
696
jsY_unescape(J);
697
}
698
699
textend(J);
700
701
return jsY_findkeyword(J, J->lexbuf.text);
702
}
703
704
if (J->lexchar >= 0x20 && J->lexchar <= 0x7E)
705
jsY_error(J, "unexpected character: '%c'", J->lexchar);
706
jsY_error(J, "unexpected character: \\u%04X", J->lexchar);
707
}
708
}
709
710
void jsY_initlex(js_State *J, const char *filename, const char *source)
711
{
712
J->filename = filename;
713
J->source = source;
714
J->line = 1;
715
J->lasttoken = 0;
716
jsY_next(J); /* load first lookahead character */
717
}
718
719
int jsY_lex(js_State *J)
720
{
721
return J->lasttoken = jsY_lexx(J);
722
}
723
724
int jsY_lexjson(js_State *J)
725
{
726
while (1) {
727
J->lexline = J->line; /* save location of beginning of token */
728
729
while (jsY_iswhite(J->lexchar) || J->lexchar == '\n')
730
jsY_next(J);
731
732
if (J->lexchar >= '0' && J->lexchar <= '9') {
733
return lexnumber(J);
734
}
735
736
switch (J->lexchar) {
737
case ',': jsY_next(J); return ',';
738
case ':': jsY_next(J); return ':';
739
case '[': jsY_next(J); return '[';
740
case ']': jsY_next(J); return ']';
741
case '{': jsY_next(J); return '{';
742
case '}': jsY_next(J); return '}';
743
744
case '"':
745
return lexstring(J);
746
747
case '.':
748
return lexnumber(J);
749
750
case 'f':
751
jsY_next(J); jsY_expect(J, 'a'); jsY_expect(J, 'l'); jsY_expect(J, 's'); jsY_expect(J, 'e');
752
return TK_FALSE;
753
754
case 'n':
755
jsY_next(J); jsY_expect(J, 'u'); jsY_expect(J, 'l'); jsY_expect(J, 'l');
756
return TK_NULL;
757
758
case 't':
759
jsY_next(J); jsY_expect(J, 'r'); jsY_expect(J, 'u'); jsY_expect(J, 'e');
760
return TK_TRUE;
761
762
case 0:
763
return 0; /* EOF */
764
}
765
766
if (J->lexchar >= 0x20 && J->lexchar <= 0x7E)
767
jsY_error(J, "unexpected character: '%c'", J->lexchar);
768
jsY_error(J, "unexpected character: \\u%04X", J->lexchar);
769
}
770
}
771
772