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 | |
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 | |
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 | |
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 | |
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 | |
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 | |