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 
jsY_error(js_State * J,const char * fmt,...)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 
jsY_tokenstring(int token)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 
jsY_findword(const char * s,const char ** list,int num)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 
jsY_findkeyword(js_State * J,const char * s)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 
jsY_iswhite(int c)110 int jsY_iswhite(int c)
111 {
112 	return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF;
113 }
114 
jsY_isnewline(int c)115 int jsY_isnewline(int c)
116 {
117 	return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;
118 }
119 
120 #ifndef isalpha
121 #define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
122 #endif
123 #ifndef isdigit
124 #define isdigit(c) (c >= '0' && c <= '9')
125 #endif
126 #ifndef ishex
127 #define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
128 #endif
129 
jsY_isidentifierstart(int c)130 static int jsY_isidentifierstart(int c)
131 {
132 	return isalpha(c) || c == '$' || c == '_' || isalpharune(c);
133 }
134 
jsY_isidentifierpart(int c)135 static int jsY_isidentifierpart(int c)
136 {
137 	return isdigit(c) || isalpha(c) || c == '$' || c == '_' || isalpharune(c);
138 }
139 
jsY_isdec(int c)140 static int jsY_isdec(int c)
141 {
142 	return isdigit(c);
143 }
144 
jsY_ishex(int c)145 int jsY_ishex(int c)
146 {
147 	return isdigit(c) || ishex(c);
148 }
149 
jsY_tohex(int c)150 int jsY_tohex(int c)
151 {
152 	if (c >= '0' && c <= '9') return c - '0';
153 	if (c >= 'a' && c <= 'f') return c - 'a' + 0xA;
154 	if (c >= 'A' && c <= 'F') return c - 'A' + 0xA;
155 	return 0;
156 }
157 
jsY_next(js_State * J)158 static void jsY_next(js_State *J)
159 {
160 	Rune c;
161 	if (*J->source == 0) {
162 		J->lexchar = EOF;
163 		return;
164 	}
165 	J->source += chartorune(&c, J->source);
166 	/* consume CR LF as one unit */
167 	if (c == '\r' && *J->source == '\n')
168 		++J->source;
169 	if (jsY_isnewline(c)) {
170 		J->line++;
171 		c = '\n';
172 	}
173 	J->lexchar = c;
174 }
175 
176 #define jsY_accept(J, x) (J->lexchar == x ? (jsY_next(J), 1) : 0)
177 
178 #define jsY_expect(J, x) if (!jsY_accept(J, x)) jsY_error(J, "expected '%c'", x)
179 
jsY_unescape(js_State * J)180 static void jsY_unescape(js_State *J)
181 {
182 	if (jsY_accept(J, '\\')) {
183 		if (jsY_accept(J, 'u')) {
184 			int x = 0;
185 			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 12; jsY_next(J);
186 			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 8; jsY_next(J);
187 			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 4; jsY_next(J);
188 			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar);
189 			J->lexchar = x;
190 			return;
191 		}
192 error:
193 		jsY_error(J, "unexpected escape sequence");
194 	}
195 }
196 
textinit(js_State * J)197 static void textinit(js_State *J)
198 {
199 	if (!J->lexbuf.text) {
200 		J->lexbuf.cap = 4096;
201 		J->lexbuf.text = js_malloc(J, J->lexbuf.cap);
202 	}
203 	J->lexbuf.len = 0;
204 }
205 
textpush(js_State * J,Rune c)206 static void textpush(js_State *J, Rune c)
207 {
208 	int n;
209 	if (c == EOF)
210 		n = 1;
211 	else
212 		n = runelen(c);
213 	if (J->lexbuf.len + n > J->lexbuf.cap) {
214 		J->lexbuf.cap = J->lexbuf.cap * 2;
215 		J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap);
216 	}
217 	if (c == EOF)
218 		J->lexbuf.text[J->lexbuf.len++] = 0;
219 	else
220 		J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c);
221 }
222 
textend(js_State * J)223 static char *textend(js_State *J)
224 {
225 	textpush(J, EOF);
226 	return J->lexbuf.text;
227 }
228 
lexlinecomment(js_State * J)229 static void lexlinecomment(js_State *J)
230 {
231 	while (J->lexchar != EOF && J->lexchar != '\n')
232 		jsY_next(J);
233 }
234 
lexcomment(js_State * J)235 static int lexcomment(js_State *J)
236 {
237 	/* already consumed initial '/' '*' sequence */
238 	while (J->lexchar != EOF) {
239 		if (jsY_accept(J, '*')) {
240 			while (J->lexchar == '*')
241 				jsY_next(J);
242 			if (jsY_accept(J, '/'))
243 				return 0;
244 		}
245 		else
246 			jsY_next(J);
247 	}
248 	return -1;
249 }
250 
lexhex(js_State * J)251 static double lexhex(js_State *J)
252 {
253 	double n = 0;
254 	if (!jsY_ishex(J->lexchar))
255 		jsY_error(J, "malformed hexadecimal number");
256 	while (jsY_ishex(J->lexchar)) {
257 		n = n * 16 + jsY_tohex(J->lexchar);
258 		jsY_next(J);
259 	}
260 	return n;
261 }
262 
263 #if 0
264 
265 static double lexinteger(js_State *J)
266 {
267 	double n = 0;
268 	if (!jsY_isdec(J->lexchar))
269 		jsY_error(J, "malformed number");
270 	while (jsY_isdec(J->lexchar)) {
271 		n = n * 10 + (J->lexchar - '0');
272 		jsY_next(J);
273 	}
274 	return n;
275 }
276 
277 static double lexfraction(js_State *J)
278 {
279 	double n = 0;
280 	double d = 1;
281 	while (jsY_isdec(J->lexchar)) {
282 		n = n * 10 + (J->lexchar - '0');
283 		d = d * 10;
284 		jsY_next(J);
285 	}
286 	return n / d;
287 }
288 
289 static double lexexponent(js_State *J)
290 {
291 	double sign;
292 	if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
293 		if (jsY_accept(J, '-')) sign = -1;
294 		else if (jsY_accept(J, '+')) sign = 1;
295 		else sign = 1;
296 		return sign * lexinteger(J);
297 	}
298 	return 0;
299 }
300 
301 static int lexnumber(js_State *J)
302 {
303 	double n;
304 	double e;
305 
306 	if (jsY_accept(J, '0')) {
307 		if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {
308 			J->number = lexhex(J);
309 			return TK_NUMBER;
310 		}
311 		if (jsY_isdec(J->lexchar))
312 			jsY_error(J, "number with leading zero");
313 		n = 0;
314 		if (jsY_accept(J, '.'))
315 			n += lexfraction(J);
316 	} else if (jsY_accept(J, '.')) {
317 		if (!jsY_isdec(J->lexchar))
318 			return '.';
319 		n = lexfraction(J);
320 	} else {
321 		n = lexinteger(J);
322 		if (jsY_accept(J, '.'))
323 			n += lexfraction(J);
324 	}
325 
326 	e = lexexponent(J);
327 	if (e < 0)
328 		n /= pow(10, -e);
329 	else if (e > 0)
330 		n *= pow(10, e);
331 
332 	if (jsY_isidentifierstart(J->lexchar))
333 		jsY_error(J, "number with letter suffix");
334 
335 	J->number = n;
336 	return TK_NUMBER;
337 }
338 
339 #else
340 
lexnumber(js_State * J)341 static int lexnumber(js_State *J)
342 {
343 	const char *s = J->source - 1;
344 
345 	if (jsY_accept(J, '0')) {
346 		if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {
347 			J->number = lexhex(J);
348 			return TK_NUMBER;
349 		}
350 		if (jsY_isdec(J->lexchar))
351 			jsY_error(J, "number with leading zero");
352 		if (jsY_accept(J, '.')) {
353 			while (jsY_isdec(J->lexchar))
354 				jsY_next(J);
355 		}
356 	} else if (jsY_accept(J, '.')) {
357 		if (!jsY_isdec(J->lexchar))
358 			return '.';
359 		while (jsY_isdec(J->lexchar))
360 			jsY_next(J);
361 	} else {
362 		while (jsY_isdec(J->lexchar))
363 			jsY_next(J);
364 		if (jsY_accept(J, '.')) {
365 			while (jsY_isdec(J->lexchar))
366 				jsY_next(J);
367 		}
368 	}
369 
370 	if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
371 		if (J->lexchar == '-' || J->lexchar == '+')
372 			jsY_next(J);
373 		if (jsY_isdec(J->lexchar))
374 			while (jsY_isdec(J->lexchar))
375 				jsY_next(J);
376 		else
377 			jsY_error(J, "missing exponent");
378 	}
379 
380 	if (jsY_isidentifierstart(J->lexchar))
381 		jsY_error(J, "number with letter suffix");
382 
383 	J->number = js_strtod(s, NULL);
384 	return TK_NUMBER;
385 }
386 
387 #endif
388 
lexescape(js_State * J)389 static int lexescape(js_State *J)
390 {
391 	int x = 0;
392 
393 	/* already consumed '\' */
394 
395 	if (jsY_accept(J, '\n'))
396 		return 0;
397 
398 	switch (J->lexchar) {
399 	case EOF: jsY_error(J, "unterminated escape sequence");
400 	case 'u':
401 		jsY_next(J);
402 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); }
403 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); }
404 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
405 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
406 		textpush(J, x);
407 		break;
408 	case 'x':
409 		jsY_next(J);
410 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
411 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
412 		textpush(J, x);
413 		break;
414 	case '0': textpush(J, 0); jsY_next(J); break;
415 	case '\\': textpush(J, '\\'); jsY_next(J); break;
416 	case '\'': textpush(J, '\''); jsY_next(J); break;
417 	case '"': textpush(J, '"'); jsY_next(J); break;
418 	case 'b': textpush(J, '\b'); jsY_next(J); break;
419 	case 'f': textpush(J, '\f'); jsY_next(J); break;
420 	case 'n': textpush(J, '\n'); jsY_next(J); break;
421 	case 'r': textpush(J, '\r'); jsY_next(J); break;
422 	case 't': textpush(J, '\t'); jsY_next(J); break;
423 	case 'v': textpush(J, '\v'); jsY_next(J); break;
424 	default: textpush(J, J->lexchar); jsY_next(J); break;
425 	}
426 	return 0;
427 }
428 
lexstring(js_State * J)429 static int lexstring(js_State *J)
430 {
431 	const char *s;
432 
433 	int q = J->lexchar;
434 	jsY_next(J);
435 
436 	textinit(J);
437 
438 	while (J->lexchar != q) {
439 		if (J->lexchar == EOF || J->lexchar == '\n')
440 			jsY_error(J, "string not terminated");
441 		if (jsY_accept(J, '\\')) {
442 			if (lexescape(J))
443 				jsY_error(J, "malformed escape sequence");
444 		} else {
445 			textpush(J, J->lexchar);
446 			jsY_next(J);
447 		}
448 	}
449 	jsY_expect(J, q);
450 
451 	s = textend(J);
452 
453 	J->text = js_intern(J, s);
454 	return TK_STRING;
455 }
456 
457 /* the ugliest language wart ever... */
isregexpcontext(int last)458 static int isregexpcontext(int last)
459 {
460 	switch (last) {
461 	case ']':
462 	case ')':
463 	case '}':
464 	case TK_IDENTIFIER:
465 	case TK_NUMBER:
466 	case TK_STRING:
467 	case TK_FALSE:
468 	case TK_NULL:
469 	case TK_THIS:
470 	case TK_TRUE:
471 		return 0;
472 	default:
473 		return 1;
474 	}
475 }
476 
lexregexp(js_State * J)477 static int lexregexp(js_State *J)
478 {
479 	const char *s;
480 	int g, m, i;
481 	int inclass = 0;
482 
483 	/* already consumed initial '/' */
484 
485 	textinit(J);
486 
487 	/* regexp body */
488 	while (J->lexchar != '/' || inclass) {
489 		if (J->lexchar == EOF || J->lexchar == '\n') {
490 			jsY_error(J, "regular expression not terminated");
491 		} else if (jsY_accept(J, '\\')) {
492 			if (jsY_accept(J, '/')) {
493 				textpush(J, '/');
494 			} else {
495 				textpush(J, '\\');
496 				if (J->lexchar == EOF || J->lexchar == '\n')
497 					jsY_error(J, "regular expression not terminated");
498 				textpush(J, J->lexchar);
499 				jsY_next(J);
500 			}
501 		} else {
502 			if (J->lexchar == '[' && !inclass)
503 				inclass = 1;
504 			if (J->lexchar == ']' && inclass)
505 				inclass = 0;
506 			textpush(J, J->lexchar);
507 			jsY_next(J);
508 		}
509 	}
510 	jsY_expect(J, '/');
511 
512 	s = textend(J);
513 
514 	/* regexp flags */
515 	g = i = m = 0;
516 
517 	while (jsY_isidentifierpart(J->lexchar)) {
518 		if (jsY_accept(J, 'g')) ++g;
519 		else if (jsY_accept(J, 'i')) ++i;
520 		else if (jsY_accept(J, 'm')) ++m;
521 		else jsY_error(J, "illegal flag in regular expression: %c", J->lexchar);
522 	}
523 
524 	if (g > 1 || i > 1 || m > 1)
525 		jsY_error(J, "duplicated flag in regular expression");
526 
527 	J->text = js_intern(J, s);
528 	J->number = 0;
529 	if (g) J->number += JS_REGEXP_G;
530 	if (i) J->number += JS_REGEXP_I;
531 	if (m) J->number += JS_REGEXP_M;
532 	return TK_REGEXP;
533 }
534 
535 /* simple "return [no Line Terminator here] ..." contexts */
isnlthcontext(int last)536 static int isnlthcontext(int last)
537 {
538 	switch (last) {
539 	case TK_BREAK:
540 	case TK_CONTINUE:
541 	case TK_RETURN:
542 	case TK_THROW:
543 		return 1;
544 	default:
545 		return 0;
546 	}
547 }
548 
jsY_lexx(js_State * J)549 static int jsY_lexx(js_State *J)
550 {
551 	J->newline = 0;
552 
553 	while (1) {
554 		J->lexline = J->line; /* save location of beginning of token */
555 
556 		while (jsY_iswhite(J->lexchar))
557 			jsY_next(J);
558 
559 		if (jsY_accept(J, '\n')) {
560 			J->newline = 1;
561 			if (isnlthcontext(J->lasttoken))
562 				return ';';
563 			continue;
564 		}
565 
566 		if (jsY_accept(J, '/')) {
567 			if (jsY_accept(J, '/')) {
568 				lexlinecomment(J);
569 				continue;
570 			} else if (jsY_accept(J, '*')) {
571 				if (lexcomment(J))
572 					jsY_error(J, "multi-line comment not terminated");
573 				continue;
574 			} else if (isregexpcontext(J->lasttoken)) {
575 				return lexregexp(J);
576 			} else if (jsY_accept(J, '=')) {
577 				return TK_DIV_ASS;
578 			} else {
579 				return '/';
580 			}
581 		}
582 
583 		if (J->lexchar >= '0' && J->lexchar <= '9') {
584 			return lexnumber(J);
585 		}
586 
587 		switch (J->lexchar) {
588 		case '(': jsY_next(J); return '(';
589 		case ')': jsY_next(J); return ')';
590 		case ',': jsY_next(J); return ',';
591 		case ':': jsY_next(J); return ':';
592 		case ';': jsY_next(J); return ';';
593 		case '?': jsY_next(J); return '?';
594 		case '[': jsY_next(J); return '[';
595 		case ']': jsY_next(J); return ']';
596 		case '{': jsY_next(J); return '{';
597 		case '}': jsY_next(J); return '}';
598 		case '~': jsY_next(J); return '~';
599 
600 		case '\'':
601 		case '"':
602 			return lexstring(J);
603 
604 		case '.':
605 			return lexnumber(J);
606 
607 		case '<':
608 			jsY_next(J);
609 			if (jsY_accept(J, '<')) {
610 				if (jsY_accept(J, '='))
611 					return TK_SHL_ASS;
612 				return TK_SHL;
613 			}
614 			if (jsY_accept(J, '='))
615 				return TK_LE;
616 			return '<';
617 
618 		case '>':
619 			jsY_next(J);
620 			if (jsY_accept(J, '>')) {
621 				if (jsY_accept(J, '>')) {
622 					if (jsY_accept(J, '='))
623 						return TK_USHR_ASS;
624 					return TK_USHR;
625 				}
626 				if (jsY_accept(J, '='))
627 					return TK_SHR_ASS;
628 				return TK_SHR;
629 			}
630 			if (jsY_accept(J, '='))
631 				return TK_GE;
632 			return '>';
633 
634 		case '=':
635 			jsY_next(J);
636 			if (jsY_accept(J, '=')) {
637 				if (jsY_accept(J, '='))
638 					return TK_STRICTEQ;
639 				return TK_EQ;
640 			}
641 			return '=';
642 
643 		case '!':
644 			jsY_next(J);
645 			if (jsY_accept(J, '=')) {
646 				if (jsY_accept(J, '='))
647 					return TK_STRICTNE;
648 				return TK_NE;
649 			}
650 			return '!';
651 
652 		case '+':
653 			jsY_next(J);
654 			if (jsY_accept(J, '+'))
655 				return TK_INC;
656 			if (jsY_accept(J, '='))
657 				return TK_ADD_ASS;
658 			return '+';
659 
660 		case '-':
661 			jsY_next(J);
662 			if (jsY_accept(J, '-'))
663 				return TK_DEC;
664 			if (jsY_accept(J, '='))
665 				return TK_SUB_ASS;
666 			return '-';
667 
668 		case '*':
669 			jsY_next(J);
670 			if (jsY_accept(J, '='))
671 				return TK_MUL_ASS;
672 			return '*';
673 
674 		case '%':
675 			jsY_next(J);
676 			if (jsY_accept(J, '='))
677 				return TK_MOD_ASS;
678 			return '%';
679 
680 		case '&':
681 			jsY_next(J);
682 			if (jsY_accept(J, '&'))
683 				return TK_AND;
684 			if (jsY_accept(J, '='))
685 				return TK_AND_ASS;
686 			return '&';
687 
688 		case '|':
689 			jsY_next(J);
690 			if (jsY_accept(J, '|'))
691 				return TK_OR;
692 			if (jsY_accept(J, '='))
693 				return TK_OR_ASS;
694 			return '|';
695 
696 		case '^':
697 			jsY_next(J);
698 			if (jsY_accept(J, '='))
699 				return TK_XOR_ASS;
700 			return '^';
701 
702 		case EOF:
703 			return 0; /* EOF */
704 		}
705 
706 		/* Handle \uXXXX escapes in identifiers */
707 		jsY_unescape(J);
708 		if (jsY_isidentifierstart(J->lexchar)) {
709 			textinit(J);
710 			textpush(J, J->lexchar);
711 
712 			jsY_next(J);
713 			jsY_unescape(J);
714 			while (jsY_isidentifierpart(J->lexchar)) {
715 				textpush(J, J->lexchar);
716 				jsY_next(J);
717 				jsY_unescape(J);
718 			}
719 
720 			textend(J);
721 
722 			return jsY_findkeyword(J, J->lexbuf.text);
723 		}
724 
725 		if (J->lexchar >= 0x20 && J->lexchar <= 0x7E)
726 			jsY_error(J, "unexpected character: '%c'", J->lexchar);
727 		jsY_error(J, "unexpected character: \\u%04X", J->lexchar);
728 	}
729 }
730 
jsY_initlex(js_State * J,const char * filename,const char * source)731 void jsY_initlex(js_State *J, const char *filename, const char *source)
732 {
733 	J->filename = filename;
734 	J->source = source;
735 	J->line = 1;
736 	J->lasttoken = 0;
737 	jsY_next(J); /* load first lookahead character */
738 }
739 
jsY_lex(js_State * J)740 int jsY_lex(js_State *J)
741 {
742 	return J->lasttoken = jsY_lexx(J);
743 }
744 
lexjsonnumber(js_State * J)745 static int lexjsonnumber(js_State *J)
746 {
747 	const char *s = J->source - 1;
748 
749 	if (J->lexchar == '-')
750 		jsY_next(J);
751 
752 	if (J->lexchar == '0')
753 		jsY_next(J);
754 	else if (J->lexchar >= '1' && J->lexchar <= '9')
755 		while (isdigit(J->lexchar))
756 			jsY_next(J);
757 	else
758 		jsY_error(J, "unexpected non-digit");
759 
760 	if (jsY_accept(J, '.')) {
761 		if (isdigit(J->lexchar))
762 			while (isdigit(J->lexchar))
763 				jsY_next(J);
764 		else
765 			jsY_error(J, "missing digits after decimal point");
766 	}
767 
768 	if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {
769 		if (J->lexchar == '-' || J->lexchar == '+')
770 			jsY_next(J);
771 		if (isdigit(J->lexchar))
772 			while (isdigit(J->lexchar))
773 				jsY_next(J);
774 		else
775 			jsY_error(J, "missing digits after exponent indicator");
776 	}
777 
778 	J->number = js_strtod(s, NULL);
779 	return TK_NUMBER;
780 }
781 
lexjsonescape(js_State * J)782 static int lexjsonescape(js_State *J)
783 {
784 	int x = 0;
785 
786 	/* already consumed '\' */
787 
788 	switch (J->lexchar) {
789 	default: jsY_error(J, "invalid escape sequence");
790 	case 'u':
791 		jsY_next(J);
792 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); }
793 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); }
794 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }
795 		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }
796 		textpush(J, x);
797 		break;
798 	case '"': textpush(J, '"'); jsY_next(J); break;
799 	case '\\': textpush(J, '\\'); jsY_next(J); break;
800 	case '/': textpush(J, '/'); jsY_next(J); break;
801 	case 'b': textpush(J, '\b'); jsY_next(J); break;
802 	case 'f': textpush(J, '\f'); jsY_next(J); break;
803 	case 'n': textpush(J, '\n'); jsY_next(J); break;
804 	case 'r': textpush(J, '\r'); jsY_next(J); break;
805 	case 't': textpush(J, '\t'); jsY_next(J); break;
806 	}
807 	return 0;
808 }
809 
lexjsonstring(js_State * J)810 static int lexjsonstring(js_State *J)
811 {
812 	const char *s;
813 
814 	textinit(J);
815 
816 	while (J->lexchar != '"') {
817 		if (J->lexchar == EOF)
818 			jsY_error(J, "unterminated string");
819 		else if (J->lexchar < 32)
820 			jsY_error(J, "invalid control character in string");
821 		else if (jsY_accept(J, '\\'))
822 			lexjsonescape(J);
823 		else {
824 			textpush(J, J->lexchar);
825 			jsY_next(J);
826 		}
827 	}
828 	jsY_expect(J, '"');
829 
830 	s = textend(J);
831 
832 	J->text = js_intern(J, s);
833 	return TK_STRING;
834 }
835 
jsY_lexjson(js_State * J)836 int jsY_lexjson(js_State *J)
837 {
838 	while (1) {
839 		J->lexline = J->line; /* save location of beginning of token */
840 
841 		while (jsY_iswhite(J->lexchar) || J->lexchar == '\n')
842 			jsY_next(J);
843 
844 		if ((J->lexchar >= '0' && J->lexchar <= '9') || J->lexchar == '-')
845 			return lexjsonnumber(J);
846 
847 		switch (J->lexchar) {
848 		case ',': jsY_next(J); return ',';
849 		case ':': jsY_next(J); return ':';
850 		case '[': jsY_next(J); return '[';
851 		case ']': jsY_next(J); return ']';
852 		case '{': jsY_next(J); return '{';
853 		case '}': jsY_next(J); return '}';
854 
855 		case '"':
856 			jsY_next(J);
857 			return lexjsonstring(J);
858 
859 		case 'f':
860 			jsY_next(J); jsY_expect(J, 'a'); jsY_expect(J, 'l'); jsY_expect(J, 's'); jsY_expect(J, 'e');
861 			return TK_FALSE;
862 
863 		case 'n':
864 			jsY_next(J); jsY_expect(J, 'u'); jsY_expect(J, 'l'); jsY_expect(J, 'l');
865 			return TK_NULL;
866 
867 		case 't':
868 			jsY_next(J); jsY_expect(J, 'r'); jsY_expect(J, 'u'); jsY_expect(J, 'e');
869 			return TK_TRUE;
870 
871 		case EOF:
872 			return 0; /* EOF */
873 		}
874 
875 		if (J->lexchar >= 0x20 && J->lexchar <= 0x7E)
876 			jsY_error(J, "unexpected character: '%c'", J->lexchar);
877 		jsY_error(J, "unexpected character: \\u%04X", J->lexchar);
878 	}
879 }
880