]> rtime.felk.cvut.cz Git - hornmich/skoda-qr-demo.git/blob - QRScanner/mobile/jni/thirdparty/mujs/jslex.c
Add MuPDF native source codes
[hornmich/skoda-qr-demo.git] / QRScanner / mobile / jni / thirdparty / mujs / jslex.c
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 }