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