1423 lines · 31.3 KB · C
RawDownload
#include "jsi.h"#include "jslex.h"#include "jsparse.h"#include "jscompile.h"#include "jsvalue.h" /* for jsV_numbertostring */ #define cexp jsC_cexp /* collision with math.h */ #define JF js_State *J, js_Function *F JS_NORETURN void jsC_error(js_State *J, js_Ast *node, const char *fmt, ...) JS_PRINTFLIKE(3,4); static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body);static void cexp(JF, js_Ast *exp);static void cstmlist(JF, js_Ast *list);static void cstm(JF, js_Ast *stm); void jsC_error(js_State *J, js_Ast *node, 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, node->line);	strcat(buf, msgbuf); 	js_newsyntaxerror(J, buf);	js_throw(J);} static const char *futurewords[] = {	"class", "const", "enum", "export", "extends", "import", "super",}; static const char *strictfuturewords[] = {	"implements", "interface", "let", "package", "private", "protected",	"public", "static", "yield",}; static void checkfutureword(JF, js_Ast *exp){	if (jsY_findword(exp->string, futurewords, nelem(futurewords)) >= 0)		jsC_error(J, exp, "'%s' is a future reserved word", exp->string);	if (F->strict) {		if (jsY_findword(exp->string, strictfuturewords, nelem(strictfuturewords)) >= 0)			jsC_error(J, exp, "'%s' is a strict mode future reserved word", exp->string);	}} static js_Function *newfun(js_State *J, int line, js_Ast *name, js_Ast *params, js_Ast *body, int script, int default_strict){	js_Function *F = js_malloc(J, sizeof *F);	memset(F, 0, sizeof *F);	F->gcmark = 0;	F->gcnext = J->gcfun;	J->gcfun = F;	++J->gccounter; 	F->filename = js_intern(J, J->filename);	F->line = line;	F->script = script;	F->strict = default_strict;	F->name = name ? name->string : ""; 	cfunbody(J, F, name, params, body); 	return F;} /* Emit opcodes, constants and jumps */ static void emitraw(JF, int value){	if (value != (js_Instruction)value)		js_syntaxerror(J, "integer overflow in instruction coding");	if (F->codelen >= F->codecap) {		F->codecap = F->codecap ? F->codecap * 2 : 64;		F->code = js_realloc(J, F->code, F->codecap * sizeof *F->code);	}	F->code[F->codelen++] = value;} static void emit(JF, int value){	emitraw(J, F, F->lastline);	emitraw(J, F, value);} static void emitarg(JF, int value){	emitraw(J, F, value);} static void emitline(JF, js_Ast *node){	F->lastline = node->line;} static int addfunction(JF, js_Function *value){	if (F->funlen >= F->funcap) {		F->funcap = F->funcap ? F->funcap * 2 : 16;		F->funtab = js_realloc(J, F->funtab, F->funcap * sizeof *F->funtab);	}	F->funtab[F->funlen] = value;	return F->funlen++;} static int addlocal(JF, js_Ast *ident, int reuse){	const char *name = ident->string;	if (F->strict) {		if (!strcmp(name, "arguments"))			jsC_error(J, ident, "redefining 'arguments' is not allowed in strict mode");		if (!strcmp(name, "eval"))			jsC_error(J, ident, "redefining 'eval' is not allowed in strict mode");	} else {		if (!strcmp(name, "eval"))			js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line);	}	if (reuse || F->strict) {		int i;		for (i = 0; i < F->varlen; ++i) {			if (!strcmp(F->vartab[i], name)) {				if (reuse)					return i+1;				if (F->strict)					jsC_error(J, ident, "duplicate formal parameter '%s'", name);			}		}	}	if (F->varlen >= F->varcap) {		F->varcap = F->varcap ? F->varcap * 2 : 16;		F->vartab = js_realloc(J, F->vartab, F->varcap * sizeof *F->vartab);	}	F->vartab[F->varlen] = name;	return ++F->varlen;} static int findlocal(JF, const char *name){	int i;	for (i = F->varlen; i > 0; --i)		if (!strcmp(F->vartab[i-1], name))			return i;	return -1;} static void emitfunction(JF, js_Function *fun){	F->lightweight = 0;	emit(J, F, OP_CLOSURE);	emitarg(J, F, addfunction(J, F, fun));} static void emitnumber(JF, double num){	if (num == 0) {		emit(J, F, OP_INTEGER);		emitarg(J, F, 32768);		if (signbit(num))			emit(J, F, OP_NEG);	} else if (num >= SHRT_MIN && num <= SHRT_MAX && num == (int)num) {		emit(J, F, OP_INTEGER);		emitarg(J, F, num + 32768);	} else {#define N (sizeof(num) / sizeof(js_Instruction))		js_Instruction x[N];		size_t i;		emit(J, F, OP_NUMBER);		memcpy(x, &num, sizeof(num));		for (i = 0; i < N; ++i)			emitarg(J, F, x[i]);#undef N	}} static void emitstring(JF, int opcode, const char *str){#define N (sizeof(str) / sizeof(js_Instruction))	js_Instruction x[N];	size_t i;	emit(J, F, opcode);	memcpy(x, &str, sizeof(str));	for (i = 0; i < N; ++i)		emitarg(J, F, x[i]);#undef N} static void emitlocal(JF, int oploc, int opvar, js_Ast *ident){	int is_arguments = !strcmp(ident->string, "arguments");	int is_eval = !strcmp(ident->string, "eval");	int i; 	if (is_arguments) {		F->lightweight = 0;		F->arguments = 1;	} 	checkfutureword(J, F, ident);	if (F->strict && oploc == OP_SETLOCAL) {		if (is_arguments)			jsC_error(J, ident, "'arguments' is read-only in strict mode");		if (is_eval)			jsC_error(J, ident, "'eval' is read-only in strict mode");	}	if (is_eval)		js_evalerror(J, "%s:%d: invalid use of 'eval'", J->filename, ident->line); 	i = findlocal(J, F, ident->string);	if (i < 0) {		emitstring(J, F, opvar, ident->string);	} else {		emit(J, F, oploc);		emitarg(J, F, i);	}} static int here(JF){	return F->codelen;} static int emitjump(JF, int opcode){	int inst;	emit(J, F, opcode);	inst = F->codelen;	emitarg(J, F, 0);	return inst;} static void emitjumpto(JF, int opcode, int dest){	emit(J, F, opcode);	if (dest != (js_Instruction)dest)		js_syntaxerror(J, "jump address integer overflow");	emitarg(J, F, dest);} static void labelto(JF, int inst, int addr){	if (addr != (js_Instruction)addr)		js_syntaxerror(J, "jump address integer overflow");	F->code[inst] = addr;} static void label(JF, int inst){	labelto(J, F, inst, F->codelen);} /* Expressions */ static void ctypeof(JF, js_Ast *exp){	if (exp->a->type == EXP_IDENTIFIER) {		emitline(J, F, exp->a);		emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->a);	} else {		cexp(J, F, exp->a);	}	emitline(J, F, exp);	emit(J, F, OP_TYPEOF);} static void cunary(JF, js_Ast *exp, int opcode){	cexp(J, F, exp->a);	emitline(J, F, exp);	emit(J, F, opcode);} static void cbinary(JF, js_Ast *exp, int opcode){	cexp(J, F, exp->a);	cexp(J, F, exp->b);	emitline(J, F, exp);	emit(J, F, opcode);} static void carray(JF, js_Ast *list){	while (list) {		emitline(J, F, list->a);		cexp(J, F, list->a);		emit(J, F, OP_INITARRAY);		list = list->b;	}} static void checkdup(JF, js_Ast *list, js_Ast *end){	char nbuf[32], sbuf[32];	const char *needle, *straw; 	if (end->a->type == EXP_NUMBER)		needle = jsV_numbertostring(J, nbuf, end->a->number);	else		needle = end->a->string; 	while (list->a != end) {		if (list->a->type == end->type) {			js_Ast *prop = list->a->a;			if (prop->type == EXP_NUMBER)				straw = jsV_numbertostring(J, sbuf, prop->number);			else				straw =  prop->string;			if (!strcmp(needle, straw))				jsC_error(J, list, "duplicate property '%s' in object literal", needle);		}		list = list->b;	}} static void cobject(JF, js_Ast *list){	js_Ast *head = list; 	while (list) {		js_Ast *kv = list->a;		js_Ast *prop = kv->a; 		if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING) {			emitline(J, F, prop);			emitstring(J, F, OP_STRING, prop->string);		} else if (prop->type == EXP_NUMBER) {			emitline(J, F, prop);			emitnumber(J, F, prop->number);		} else {			jsC_error(J, prop, "invalid property name in object initializer");		} 		if (F->strict)			checkdup(J, F, head, kv); 		switch (kv->type) {		default: /* impossible */ break;		case EXP_PROP_VAL:			cexp(J, F, kv->b);			emitline(J, F, kv);			emit(J, F, OP_INITPROP);			break;		case EXP_PROP_GET:			emitfunction(J, F, newfun(J, prop->line, NULL, NULL, kv->c, 0, F->strict));			emitline(J, F, kv);			emit(J, F, OP_INITGETTER);			break;		case EXP_PROP_SET:			emitfunction(J, F, newfun(J, prop->line, NULL, kv->b, kv->c, 0, F->strict));			emitline(J, F, kv);			emit(J, F, OP_INITSETTER);			break;		} 		list = list->b;	}} static int cargs(JF, js_Ast *list){	int n = 0;	while (list) {		cexp(J, F, list->a);		list = list->b;		++n;	}	return n;} static void cassign(JF, js_Ast *exp){	js_Ast *lhs = exp->a;	js_Ast *rhs = exp->b;	switch (lhs->type) {	case EXP_IDENTIFIER:		cexp(J, F, rhs);		emitline(J, F, exp);		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);		break;	case EXP_INDEX:		cexp(J, F, lhs->a);		cexp(J, F, lhs->b);		cexp(J, F, rhs);		emitline(J, F, exp);		emit(J, F, OP_SETPROP);		break;	case EXP_MEMBER:		cexp(J, F, lhs->a);		cexp(J, F, rhs);		emitline(J, F, exp);		emitstring(J, F, OP_SETPROP_S, lhs->b->string);		break;	default:		jsC_error(J, lhs, "invalid l-value in assignment");	}} static void cassignforin(JF, js_Ast *stm){	js_Ast *lhs = stm->a; 	if (stm->type == STM_FOR_IN_VAR) {		if (lhs->b)			jsC_error(J, lhs->b, "more than one loop variable in for-in statement");		emitline(J, F, lhs->a);		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs->a->a); /* list(var-init(ident)) */		emit(J, F, OP_POP);		return;	} 	switch (lhs->type) {	case EXP_IDENTIFIER:		emitline(J, F, lhs);		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);		emit(J, F, OP_POP);		break;	case EXP_INDEX:		cexp(J, F, lhs->a);		cexp(J, F, lhs->b);		emitline(J, F, lhs);		emit(J, F, OP_ROT3);		emit(J, F, OP_SETPROP);		emit(J, F, OP_POP);		break;	case EXP_MEMBER:		cexp(J, F, lhs->a);		emitline(J, F, lhs);		emit(J, F, OP_ROT2);		emitstring(J, F, OP_SETPROP_S, lhs->b->string);		emit(J, F, OP_POP);		break;	default:		jsC_error(J, lhs, "invalid l-value in for-in loop assignment");	}} static void cassignop1(JF, js_Ast *lhs){	switch (lhs->type) {	case EXP_IDENTIFIER:		emitline(J, F, lhs);		emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, lhs);		break;	case EXP_INDEX:		cexp(J, F, lhs->a);		cexp(J, F, lhs->b);		emitline(J, F, lhs);		emit(J, F, OP_DUP2);		emit(J, F, OP_GETPROP);		break;	case EXP_MEMBER:		cexp(J, F, lhs->a);		emitline(J, F, lhs);		emit(J, F, OP_DUP);		emitstring(J, F, OP_GETPROP_S, lhs->b->string);		break;	default:		jsC_error(J, lhs, "invalid l-value in assignment");	}} static void cassignop2(JF, js_Ast *lhs, int postfix){	switch (lhs->type) {	case EXP_IDENTIFIER:		emitline(J, F, lhs);		if (postfix) emit(J, F, OP_ROT2);		emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs);		break;	case EXP_INDEX:		emitline(J, F, lhs);		if (postfix) emit(J, F, OP_ROT4);		emit(J, F, OP_SETPROP);		break;	case EXP_MEMBER:		emitline(J, F, lhs);		if (postfix) emit(J, F, OP_ROT3);		emitstring(J, F, OP_SETPROP_S, lhs->b->string);		break;	default:		jsC_error(J, lhs, "invalid l-value in assignment");	}} static void cassignop(JF, js_Ast *exp, int opcode){	js_Ast *lhs = exp->a;	js_Ast *rhs = exp->b;	cassignop1(J, F, lhs);	cexp(J, F, rhs);	emitline(J, F, exp);	emit(J, F, opcode);	cassignop2(J, F, lhs, 0);}

Lines 1–500 of 1423.

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