879 lines · 19.4 KB · C
RawDownload
#include "jsi.h"#include "jslex.h"#include "utf.h" JS_NORETURN static void jsY_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); static void jsY_error(js_State *J, const char *fmt, ...){	va_list ap;	char buf[512];	char msgbuf[256]; 	va_start(ap, fmt);	vsnprintf(msgbuf, 256, fmt, ap);	va_end(ap); 	snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline);	strcat(buf, msgbuf); 	js_newsyntaxerror(J, buf);	js_throw(J);} static const char *tokenstring[] = {	"(end-of-file)",	"'\\x01'", "'\\x02'", "'\\x03'", "'\\x04'", "'\\x05'", "'\\x06'", "'\\x07'",	"'\\x08'", "'\\x09'", "'\\x0A'", "'\\x0B'", "'\\x0C'", "'\\x0D'", "'\\x0E'", "'\\x0F'",	"'\\x10'", "'\\x11'", "'\\x12'", "'\\x13'", "'\\x14'", "'\\x15'", "'\\x16'", "'\\x17'",	"'\\x18'", "'\\x19'", "'\\x1A'", "'\\x1B'", "'\\x1C'", "'\\x1D'", "'\\x1E'", "'\\x1F'",	"' '", "'!'", "'\"'", "'#'", "'$'", "'%'", "'&'", "'\\''",	"'('", "')'", "'*'", "'+'", "','", "'-'", "'.'", "'/'",	"'0'", "'1'", "'2'", "'3'", "'4'", "'5'", "'6'", "'7'",	"'8'", "'9'", "':'", "';'", "'<'", "'='", "'>'", "'?'",	"'@'", "'A'", "'B'", "'C'", "'D'", "'E'", "'F'", "'G'",	"'H'", "'I'", "'J'", "'K'", "'L'", "'M'", "'N'", "'O'",	"'P'", "'Q'", "'R'", "'S'", "'T'", "'U'", "'V'", "'W'",	"'X'", "'Y'", "'Z'", "'['", "'\'", "']'", "'^'", "'_'",	"'`'", "'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'",	"'h'", "'i'", "'j'", "'k'", "'l'", "'m'", "'n'", "'o'",	"'p'", "'q'", "'r'", "'s'", "'t'", "'u'", "'v'", "'w'",	"'x'", "'y'", "'z'", "'{'", "'|'", "'}'", "'~'", "'\\x7F'", 	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,	0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 	"(identifier)", "(number)", "(string)", "(regexp)", 	"'<='", "'>='", "'=='", "'!='", "'==='", "'!=='",	"'<<'", "'>>'", "'>>>'", "'&&'", "'||'",	"'+='", "'-='", "'*='", "'/='", "'%='",	"'<<='", "'>>='", "'>>>='", "'&='", "'|='", "'^='",	"'++'", "'--'", 	"'break'", "'case'", "'catch'", "'continue'", "'debugger'",	"'default'", "'delete'", "'do'", "'else'", "'false'", "'finally'", "'for'",	"'function'", "'if'", "'in'", "'instanceof'", "'new'", "'null'", "'return'",	"'switch'", "'this'", "'throw'", "'true'", "'try'", "'typeof'", "'var'",	"'void'", "'while'", "'with'",}; const char *jsY_tokenstring(int token){	if (token >= 0 && token < (int)nelem(tokenstring))		if (tokenstring[token])			return tokenstring[token];	return "<unknown>";} static const char *keywords[] = {	"break", "case", "catch", "continue", "debugger", "default", "delete",	"do", "else", "false", "finally", "for", "function", "if", "in",	"instanceof", "new", "null", "return", "switch", "this", "throw",	"true", "try", "typeof", "var", "void", "while", "with",}; int jsY_findword(const char *s, const char **list, int num){	int l = 0;	int r = num - 1;	while (l <= r) {		int m = (l + r) >> 1;		int c = strcmp(s, list[m]);		if (c < 0)			r = m - 1;		else if (c > 0)			l = m + 1;		else			return m;	}	return -1;} static int jsY_findkeyword(js_State *J, const char *s){	int i = jsY_findword(s, keywords, nelem(keywords));	if (i >= 0) {		J->text = keywords[i];		return TK_BREAK + i; /* first keyword + i */	}	J->text = js_intern(J, s);	return TK_IDENTIFIER;} int jsY_iswhite(int c){	return c == 0x9 || c == 0xB || c == 0xC || c == 0x20 || c == 0xA0 || c == 0xFEFF;} int jsY_isnewline(int c){	return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029;} #ifndef isalpha#define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))#endif#ifndef isdigit#define isdigit(c) (c >= '0' && c <= '9')#endif#ifndef ishex#define ishex(c) ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))#endif static int jsY_isidentifierstart(int c){	return isalpha(c) || c == '$' || c == '_' || isalpharune(c);} static int jsY_isidentifierpart(int c){	return isdigit(c) || isalpha(c) || c == '$' || c == '_' || isalpharune(c);} static int jsY_isdec(int c){	return isdigit(c);} int jsY_ishex(int c){	return isdigit(c) || ishex(c);} int jsY_tohex(int c){	if (c >= '0' && c <= '9') return c - '0';	if (c >= 'a' && c <= 'f') return c - 'a' + 0xA;	if (c >= 'A' && c <= 'F') return c - 'A' + 0xA;	return 0;} static void jsY_next(js_State *J){	Rune c;	if (*J->source == 0) {		J->lexchar = EOF;		return;	}	J->source += chartorune(&c, J->source);	/* consume CR LF as one unit */	if (c == '\r' && *J->source == '\n')		++J->source;	if (jsY_isnewline(c)) {		J->line++;		c = '\n';	}	J->lexchar = c;} #define jsY_accept(J, x) (J->lexchar == x ? (jsY_next(J), 1) : 0) #define jsY_expect(J, x) if (!jsY_accept(J, x)) jsY_error(J, "expected '%c'", x) static void jsY_unescape(js_State *J){	if (jsY_accept(J, '\\')) {		if (jsY_accept(J, 'u')) {			int x = 0;			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 12; jsY_next(J);			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 8; jsY_next(J);			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar) << 4; jsY_next(J);			if (!jsY_ishex(J->lexchar)) { goto error; } x |= jsY_tohex(J->lexchar);			J->lexchar = x;			return;		}error:		jsY_error(J, "unexpected escape sequence");	}} static void textinit(js_State *J){	if (!J->lexbuf.text) {		J->lexbuf.cap = 4096;		J->lexbuf.text = js_malloc(J, J->lexbuf.cap);	}	J->lexbuf.len = 0;} static void textpush(js_State *J, Rune c){	int n;	if (c == EOF)		n = 1;	else		n = runelen(c);	if (J->lexbuf.len + n > J->lexbuf.cap) {		J->lexbuf.cap = J->lexbuf.cap * 2;		J->lexbuf.text = js_realloc(J, J->lexbuf.text, J->lexbuf.cap);	}	if (c == EOF)		J->lexbuf.text[J->lexbuf.len++] = 0;	else		J->lexbuf.len += runetochar(J->lexbuf.text + J->lexbuf.len, &c);} static char *textend(js_State *J){	textpush(J, EOF);	return J->lexbuf.text;} static void lexlinecomment(js_State *J){	while (J->lexchar != EOF && J->lexchar != '\n')		jsY_next(J);} static int lexcomment(js_State *J){	/* already consumed initial '/' '*' sequence */	while (J->lexchar != EOF) {		if (jsY_accept(J, '*')) {			while (J->lexchar == '*')				jsY_next(J);			if (jsY_accept(J, '/'))				return 0;		}		else			jsY_next(J);	}	return -1;} static double lexhex(js_State *J){	double n = 0;	if (!jsY_ishex(J->lexchar))		jsY_error(J, "malformed hexadecimal number");	while (jsY_ishex(J->lexchar)) {		n = n * 16 + jsY_tohex(J->lexchar);		jsY_next(J);	}	return n;} #if 0 static double lexinteger(js_State *J){	double n = 0;	if (!jsY_isdec(J->lexchar))		jsY_error(J, "malformed number");	while (jsY_isdec(J->lexchar)) {		n = n * 10 + (J->lexchar - '0');		jsY_next(J);	}	return n;} static double lexfraction(js_State *J){	double n = 0;	double d = 1;	while (jsY_isdec(J->lexchar)) {		n = n * 10 + (J->lexchar - '0');		d = d * 10;		jsY_next(J);	}	return n / d;} static double lexexponent(js_State *J){	double sign;	if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {		if (jsY_accept(J, '-')) sign = -1;		else if (jsY_accept(J, '+')) sign = 1;		else sign = 1;		return sign * lexinteger(J);	}	return 0;} static int lexnumber(js_State *J){	double n;	double e; 	if (jsY_accept(J, '0')) {		if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {			J->number = lexhex(J);			return TK_NUMBER;		}		if (jsY_isdec(J->lexchar))			jsY_error(J, "number with leading zero");		n = 0;		if (jsY_accept(J, '.'))			n += lexfraction(J);	} else if (jsY_accept(J, '.')) {		if (!jsY_isdec(J->lexchar))			return '.';		n = lexfraction(J);	} else {		n = lexinteger(J);		if (jsY_accept(J, '.'))			n += lexfraction(J);	} 	e = lexexponent(J);	if (e < 0)		n /= pow(10, -e);	else if (e > 0)		n *= pow(10, e); 	if (jsY_isidentifierstart(J->lexchar))		jsY_error(J, "number with letter suffix"); 	J->number = n;	return TK_NUMBER;} #else static int lexnumber(js_State *J){	const char *s = J->source - 1; 	if (jsY_accept(J, '0')) {		if (jsY_accept(J, 'x') || jsY_accept(J, 'X')) {			J->number = lexhex(J);			return TK_NUMBER;		}		if (jsY_isdec(J->lexchar))			jsY_error(J, "number with leading zero");		if (jsY_accept(J, '.')) {			while (jsY_isdec(J->lexchar))				jsY_next(J);		}	} else if (jsY_accept(J, '.')) {		if (!jsY_isdec(J->lexchar))			return '.';		while (jsY_isdec(J->lexchar))			jsY_next(J);	} else {		while (jsY_isdec(J->lexchar))			jsY_next(J);		if (jsY_accept(J, '.')) {			while (jsY_isdec(J->lexchar))				jsY_next(J);		}	} 	if (jsY_accept(J, 'e') || jsY_accept(J, 'E')) {		if (J->lexchar == '-' || J->lexchar == '+')			jsY_next(J);		if (jsY_isdec(J->lexchar))			while (jsY_isdec(J->lexchar))				jsY_next(J);		else			jsY_error(J, "missing exponent");	} 	if (jsY_isidentifierstart(J->lexchar))		jsY_error(J, "number with letter suffix"); 	J->number = js_strtod(s, NULL);	return TK_NUMBER;} #endif static int lexescape(js_State *J){	int x = 0; 	/* already consumed '\' */ 	if (jsY_accept(J, '\n'))		return 0; 	switch (J->lexchar) {	case EOF: jsY_error(J, "unterminated escape sequence");	case 'u':		jsY_next(J);		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 12; jsY_next(J); }		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 8; jsY_next(J); }		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }		textpush(J, x);		break;	case 'x':		jsY_next(J);		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar) << 4; jsY_next(J); }		if (!jsY_ishex(J->lexchar)) return 1; else { x |= jsY_tohex(J->lexchar); jsY_next(J); }		textpush(J, x);		break;	case '0': textpush(J, 0); jsY_next(J); break;	case '\\': textpush(J, '\\'); jsY_next(J); break;	case '\'': textpush(J, '\''); jsY_next(J); break;	case '"': textpush(J, '"'); jsY_next(J); break;	case 'b': textpush(J, '\b'); jsY_next(J); break;	case 'f': textpush(J, '\f'); jsY_next(J); break;	case 'n': textpush(J, '\n'); jsY_next(J); break;	case 'r': textpush(J, '\r'); jsY_next(J); break;	case 't': textpush(J, '\t'); jsY_next(J); break;	case 'v': textpush(J, '\v'); jsY_next(J); break;	default: textpush(J, J->lexchar); jsY_next(J); break;	}	return 0;} static int lexstring(js_State *J){	const char *s; 	int q = J->lexchar;	jsY_next(J); 	textinit(J); 	while (J->lexchar != q) {		if (J->lexchar == EOF || J->lexchar == '\n')			jsY_error(J, "string not terminated");		if (jsY_accept(J, '\\')) {			if (lexescape(J))				jsY_error(J, "malformed escape sequence");		} else {			textpush(J, J->lexchar);			jsY_next(J);		}	}	jsY_expect(J, q); 	s = textend(J); 	J->text = js_intern(J, s);	return TK_STRING;} /* the ugliest language wart ever... */static int isregexpcontext(int last){	switch (last) {	case ']':	case ')':	case '}':	case TK_IDENTIFIER:	case TK_NUMBER:	case TK_STRING:	case TK_FALSE:	case TK_NULL:	case TK_THIS:	case TK_TRUE:		return 0;	default:		return 1;	}} static int lexregexp(js_State *J){	const char *s;	int g, m, i;	int inclass = 0; 	/* already consumed initial '/' */ 	textinit(J); 	/* regexp body */	while (J->lexchar != '/' || inclass) {		if (J->lexchar == EOF || J->lexchar == '\n') {			jsY_error(J, "regular expression not terminated");		} else if (jsY_accept(J, '\\')) {			if (jsY_accept(J, '/')) {				textpush(J, '/');			} else {				textpush(J, '\\');				if (J->lexchar == EOF || J->lexchar == '\n')					jsY_error(J, "regular expression not terminated");				textpush(J, J->lexchar);				jsY_next(J);			}

Lines 1–500 of 879.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t