1 #include "jsi.h"
2 #include "jsvalue.h"
3 #include "jsbuiltin.h"
4 
5 #define QQ(X) #X
6 #define Q(X) QQ(X)
7 
jsB_stacktrace(js_State * J,int skip)8 static int jsB_stacktrace(js_State *J, int skip)
9 {
10 	char buf[256];
11 	int n = J->tracetop - skip;
12 	if (n <= 0)
13 		return 0;
14 	for (; n > 0; --n) {
15 		const char *name = J->trace[n].name;
16 		const char *file = J->trace[n].file;
17 		int line = J->trace[n].line;
18 		if (line > 0) {
19 			if (name[0])
20 				snprintf(buf, sizeof buf, "\n\tat %s (%s:%d)", name, file, line);
21 			else
22 				snprintf(buf, sizeof buf, "\n\tat %s:%d", file, line);
23 		} else
24 			snprintf(buf, sizeof buf, "\n\tat %s (%s)", name, file);
25 		js_pushstring(J, buf);
26 		if (n < J->tracetop - skip)
27 			js_concat(J);
28 	}
29 	return 1;
30 }
31 
Ep_toString(js_State * J)32 static void Ep_toString(js_State *J)
33 {
34 	const char *name = "Error";
35 	const char *message = "";
36 
37 	if (!js_isobject(J, -1))
38 		js_typeerror(J, "not an object");
39 
40 	if (js_hasproperty(J, 0, "name"))
41 		name = js_tostring(J, -1);
42 	if (js_hasproperty(J, 0, "message"))
43 		message = js_tostring(J, -1);
44 
45 	if (name[0] == 0)
46 		js_pushstring(J, message);
47 	else if (message[0] == 0)
48 		js_pushstring(J, name);
49 	else {
50 		js_pushstring(J, name);
51 		js_pushstring(J, ": ");
52 		js_concat(J);
53 		js_pushstring(J, message);
54 		js_concat(J);
55 	}
56 }
57 
jsB_ErrorX(js_State * J,js_Object * prototype)58 static int jsB_ErrorX(js_State *J, js_Object *prototype)
59 {
60 	js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
61 	if (js_isdefined(J, 1)) {
62 		js_pushstring(J, js_tostring(J, 1));
63 		js_defproperty(J, -2, "message", JS_DONTENUM);
64 	}
65 	if (jsB_stacktrace(J, 1))
66 		js_defproperty(J, -2, "stackTrace", JS_DONTENUM);
67 	return 1;
68 }
69 
js_newerrorx(js_State * J,const char * message,js_Object * prototype)70 static void js_newerrorx(js_State *J, const char *message, js_Object *prototype)
71 {
72 	js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
73 	js_pushstring(J, message);
74 	js_setproperty(J, -2, "message");
75 	if (jsB_stacktrace(J, 0))
76 		js_setproperty(J, -2, "stackTrace");
77 }
78 
79 #define DERROR(name, Name) \
80 	static void jsB_##Name(js_State *J) { \
81 		jsB_ErrorX(J, J->Name##_prototype); \
82 	} \
83 	void js_new##name(js_State *J, const char *s) { \
84 		js_newerrorx(J, s, J->Name##_prototype); \
85 	} \
86 	void js_##name(js_State *J, const char *fmt, ...) { \
87 		va_list ap; \
88 		char buf[256]; \
89 		va_start(ap, fmt); \
90 		vsnprintf(buf, sizeof buf, fmt, ap); \
91 		va_end(ap); \
92 		js_newerrorx(J, buf, J->Name##_prototype); \
93 		js_throw(J); \
94 	}
95 
DERROR(error,Error)96 DERROR(error, Error)
97 DERROR(evalerror, EvalError)
98 DERROR(rangeerror, RangeError)
99 DERROR(referenceerror, ReferenceError)
100 DERROR(syntaxerror, SyntaxError)
101 DERROR(typeerror, TypeError)
102 DERROR(urierror, URIError)
103 
104 #undef DERROR
105 
106 void jsB_initerror(js_State *J)
107 {
108 	js_pushobject(J, J->Error_prototype);
109 	{
110 			jsB_props(J, "name", "Error");
111 			jsB_propf(J, "Error.prototype.toString", Ep_toString, 0);
112 	}
113 	js_newcconstructor(J, jsB_Error, jsB_Error, "Error", 1);
114 	js_defglobal(J, "Error", JS_DONTENUM);
115 
116 	#define IERROR(NAME) \
117 		js_pushobject(J, J->NAME##_prototype); \
118 		jsB_props(J, "name", Q(NAME)); \
119 		js_newcconstructor(J, jsB_##NAME, jsB_##NAME, Q(NAME), 1); \
120 		js_defglobal(J, Q(NAME), JS_DONTENUM);
121 
122 	IERROR(EvalError);
123 	IERROR(RangeError);
124 	IERROR(ReferenceError);
125 	IERROR(SyntaxError);
126 	IERROR(TypeError);
127 	IERROR(URIError);
128 
129 	#undef IERROR
130 }
131