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 	int top = js_gettop(J);
61 	js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
62 	if (top > 1) {
63 		js_pushstring(J, js_tostring(J, 1));
64 		js_setproperty(J, -2, "message");
65 	}
66 	if (jsB_stacktrace(J, 1))
67 		js_setproperty(J, -2, "stackTrace");
68 	return 1;
69 }
70 
js_newerrorx(js_State * J,const char * message,js_Object * prototype)71 static void js_newerrorx(js_State *J, const char *message, js_Object *prototype)
72 {
73 	js_pushobject(J, jsV_newobject(J, JS_CERROR, prototype));
74 	js_pushstring(J, message);
75 	js_setproperty(J, -2, "message");
76 	if (jsB_stacktrace(J, 0))
77 		js_setproperty(J, -2, "stackTrace");
78 }
79 
80 #define DERROR(name, Name) \
81 	static void jsB_##Name(js_State *J) { \
82 		jsB_ErrorX(J, J->Name##_prototype); \
83 	} \
84 	void js_new##name(js_State *J, const char *s) { \
85 		js_newerrorx(J, s, J->Name##_prototype); \
86 	} \
87 	void js_##name(js_State *J, const char *fmt, ...) { \
88 		va_list ap; \
89 		char buf[256]; \
90 		va_start(ap, fmt); \
91 		vsnprintf(buf, sizeof buf, fmt, ap); \
92 		va_end(ap); \
93 		js_newerrorx(J, buf, J->Name##_prototype); \
94 		js_throw(J); \
95 	}
96 
DERROR(error,Error)97 DERROR(error, Error)
98 DERROR(evalerror, EvalError)
99 DERROR(rangeerror, RangeError)
100 DERROR(referenceerror, ReferenceError)
101 DERROR(syntaxerror, SyntaxError)
102 DERROR(typeerror, TypeError)
103 DERROR(urierror, URIError)
104 
105 #undef DERROR
106 
107 void jsB_initerror(js_State *J)
108 {
109 	js_pushobject(J, J->Error_prototype);
110 	{
111 			jsB_props(J, "name", "Error");
112 			jsB_props(J, "message", "an error has occurred");
113 			jsB_propf(J, "Error.prototype.toString", Ep_toString, 0);
114 	}
115 	js_newcconstructor(J, jsB_Error, jsB_Error, "Error", 1);
116 	js_defglobal(J, "Error", JS_DONTENUM);
117 
118 	#define IERROR(NAME) \
119 		js_pushobject(J, J->NAME##_prototype); \
120 		jsB_props(J, "name", Q(NAME)); \
121 		js_newcconstructor(J, jsB_##NAME, jsB_##NAME, Q(NAME), 1); \
122 		js_defglobal(J, Q(NAME), JS_DONTENUM);
123 
124 	IERROR(EvalError);
125 	IERROR(RangeError);
126 	IERROR(ReferenceError);
127 	IERROR(SyntaxError);
128 	IERROR(TypeError);
129 	IERROR(URIError);
130 
131 	#undef IERROR
132 }
133